diff options
Diffstat (limited to 'packages')
39 files changed, 1019 insertions, 333 deletions
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java index 2e0bece..202402f 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java +++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java @@ -449,7 +449,7 @@ public class CopyService extends IntentService { InputStream src = null; OutputStream dst = null; - boolean errorOccurred = false; + IOException copyError = null; try { srcFile = mSrcClient.openFile(srcUri, "r", canceller); dstFile = mDstClient.openFile(dstUri, "w", canceller); @@ -462,16 +462,14 @@ public class CopyService extends IntentService { dst.write(buffer, 0, len); makeProgress(len); } + srcFile.checkError(); - dstFile.checkError(); } catch (IOException e) { - errorOccurred = true; - Log.e(TAG, "Error while copying " + srcUri.toString(), e); + copyError = e; try { - mFailedFiles.add(DocumentInfo.fromUri(getContentResolver(), srcUri)); - } catch (FileNotFoundException ignore) { - Log.w(TAG, "Source file gone: " + srcUri, e); - // The source file is gone. + dstFile.closeWithError(copyError.getMessage()); + } catch (IOException closeError) { + Log.e(TAG, "Error closing destination", closeError); } } finally { // This also ensures the file descriptors are closed. @@ -479,7 +477,18 @@ public class CopyService extends IntentService { IoUtils.closeQuietly(dst); } - if (errorOccurred || mIsCancelled) { + if (copyError != null) { + // Log errors. + Log.e(TAG, "Error while copying " + srcUri.toString(), copyError); + try { + mFailedFiles.add(DocumentInfo.fromUri(getContentResolver(), srcUri)); + } catch (FileNotFoundException ignore) { + Log.w(TAG, "Source file gone: " + srcUri, copyError); + // The source file is gone. + } + } + + if (copyError != null || mIsCancelled) { // Clean up half-copied files. canceller.cancel(); try { diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java index 13f7daa..b1c84dd 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java @@ -16,23 +16,21 @@ package com.android.documentsui; -import static com.android.documentsui.model.DocumentInfo.getCursorString; - -import android.app.NotificationManager; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; +import android.content.pm.ProviderInfo; +import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; -import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.os.RemoteException; import android.provider.DocumentsContract; -import android.provider.DocumentsContract.Document; import android.test.MoreAsserts; import android.test.ServiceTestCase; +import android.test.mock.MockContentResolver; import android.util.Log; import com.android.documentsui.model.DocumentInfo; @@ -43,40 +41,93 @@ import com.google.common.collect.Lists; import libcore.io.IoUtils; import libcore.io.Streams; -import org.mockito.Mockito; - +import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.OutputStream; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; public class CopyTest extends ServiceTestCase<CopyService> { + /** + * A test resolver that enables this test suite to listen for notifications that mark when copy + * operations are done. + */ + class TestContentResolver extends MockContentResolver { + private CountDownLatch mReadySignal; + private CountDownLatch mNotificationSignal; + + public TestContentResolver() { + mReadySignal = new CountDownLatch(1); + } + + /** + * Wait for the given number of files to be copied to destination. Times out after 1 sec. + */ + public void waitForChanges(int count) throws Exception { + // Wait for no more than 1 second by default. + waitForChanges(count, 1000); + } + + /** + * Wait for files to be copied to destination. + * + * @param count Number of files to wait for. + * @param timeOut Timeout in ms. TimeoutException will be thrown if this function times out. + */ + public void waitForChanges(int count, int timeOut) throws Exception { + mNotificationSignal = new CountDownLatch(count); + // Signal that the test is now waiting for files. + mReadySignal.countDown(); + if (!mNotificationSignal.await(timeOut, TimeUnit.MILLISECONDS)) { + throw new TimeoutException("Timed out waiting for files to be copied."); + } + } + + @Override + public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) { + // Wait until the test is ready to receive file notifications. + try { + mReadySignal.await(); + } catch (InterruptedException e) { + Log.d(TAG, "Interrupted while waiting for file copy readiness"); + Thread.currentThread().interrupt(); + } + if (DocumentsContract.isDocumentUri(mContext, uri)) { + Log.d(TAG, "Notification: " + uri); + // Watch for document URI change notifications - this signifies the end of a copy. + mNotificationSignal.countDown(); + } + } + }; + public CopyTest() { super(CopyService.class); } - private static String TAG = "CopyTest"; - // This must match the authority for the StubProvider. private static String AUTHORITY = "com.android.documentsui.stubprovider"; + private static String DST = "sd1"; + private static String SRC = "sd0"; + private static String TAG = "CopyTest"; private List<RootInfo> mRoots; private Context mContext; - private ContentResolver mResolver; + private TestContentResolver mResolver; private ContentProviderClient mClient; - private NotificationManager mNotificationManager; + private StubProvider mStorage; + private Context mSystemContext; @Override protected void setUp() throws Exception { super.setUp(); - setupTestContext(); - mResolver = mContext.getContentResolver(); + setupTestContext(); mClient = mResolver.acquireContentProviderClient(AUTHORITY); // Reset the stub provider's storage. - mClient.call("clear", "", null); + mStorage.clearCacheAndBuildRoots(); mRoots = Lists.newArrayList(); Uri queryUri = DocumentsContract.buildRootsUri(AUTHORITY); @@ -84,9 +135,7 @@ public class CopyTest extends ServiceTestCase<CopyService> { try { cursor = mClient.query(queryUri, null, null, null, null); while (cursor.moveToNext()) { - final RootInfo root = RootInfo.fromRootsCursor(AUTHORITY, cursor); - final String id = root.rootId; - mRoots.add(root); + mRoots.add(RootInfo.fromRootsCursor(AUTHORITY, cursor)); } } finally { IoUtils.closeQuietly(cursor); @@ -100,68 +149,94 @@ public class CopyTest extends ServiceTestCase<CopyService> { super.tearDown(); } - public List<Uri> setupTestFiles() throws Exception { - Uri rootUri = DocumentsContract.buildDocumentUri(AUTHORITY, mRoots.get(0).documentId); - List<Uri> testFiles = Lists.newArrayList( - DocumentsContract.createDocument(mClient, rootUri, "text/plain", "test0.txt"), - DocumentsContract.createDocument(mClient, rootUri, "text/plain", "test1.txt"), - DocumentsContract.createDocument(mClient, rootUri, "text/plain", "test2.txt") - ); - String testContent[] = { - "The five boxing wizards jump quickly", - "The quick brown fox jumps over the lazy dog", - "Jackdaws love my big sphinx of quartz" - }; - for (int i = 0; i < testFiles.size(); ++i) { - ParcelFileDescriptor pfd = null; - OutputStream out = null; - try { - pfd = mClient.openFile(testFiles.get(i), "w"); - out = new ParcelFileDescriptor.AutoCloseOutputStream(pfd); - out.write(testContent[i].getBytes()); - } finally { - IoUtils.closeQuietly(out); - } - } - return testFiles; - } - /** * Test copying a single file. */ public void testCopyFile() throws Exception { - Uri testFile = setupTestFiles().get(0); + String srcPath = "/test0.txt"; + Uri testFile = mStorage.createFile(SRC, srcPath, "text/plain", + "The five boxing wizards jump quickly".getBytes()); + + assertDstFileCountEquals(0); - // Just copy one file. copyToDestination(Lists.newArrayList(testFile)); - // A call to NotificationManager.cancel marks the end of the copy operation. - Mockito.verify(mNotificationManager, Mockito.timeout(1000)).cancel(Mockito.anyString(), - Mockito.anyInt()); + // 2 operations: file creation, then writing data. + mResolver.waitForChanges(2); // Verify that one file was copied; check file contents. assertDstFileCountEquals(1); - assertCopied(testFile); + assertCopied(srcPath); } /** * Test copying multiple files. */ public void testCopyMultipleFiles() throws Exception { - List<Uri> testFiles = setupTestFiles(); + String testContent[] = { + "The five boxing wizards jump quickly", + "The quick brown fox jumps over the lazy dog", + "Jackdaws love my big sphinx of quartz" + }; + String srcPaths[] = { + "/test0.txt", + "/test1.txt", + "/test2.txt" + }; + List<Uri> testFiles = Lists.newArrayList( + mStorage.createFile(SRC, srcPaths[0], "text/plain", testContent[0].getBytes()), + mStorage.createFile(SRC, srcPaths[1], "text/plain", testContent[1].getBytes()), + mStorage.createFile(SRC, srcPaths[2], "text/plain", testContent[2].getBytes())); + + assertDstFileCountEquals(0); + // Copy all the test files. copyToDestination(testFiles); - // A call to NotificationManager.cancel marks the end of the copy operation. - Mockito.verify(mNotificationManager, Mockito.timeout(1000)).cancel(Mockito.anyString(), - Mockito.anyInt()); + // 3 file creations, 3 file writes. + mResolver.waitForChanges(6); assertDstFileCountEquals(3); - for (Uri testFile : testFiles) { - assertCopied(testFile); + for (String path : srcPaths) { + assertCopied(path); } } + public void testCopyEmptyDir() throws Exception { + String srcPath = "/emptyDir"; + Uri testDir = mStorage.createFile(SRC, srcPath, DocumentsContract.Document.MIME_TYPE_DIR, + null); + + assertDstFileCountEquals(0); + + copyToDestination(Lists.newArrayList(testDir)); + + // Just 1 operation: Directory creation. + mResolver.waitForChanges(1); + + assertDstFileCountEquals(1); + + File dst = mStorage.getFile(DST, srcPath); + assertTrue(dst.isDirectory()); + } + + public void testReadErrors() throws Exception { + String srcPath = "/test0.txt"; + Uri testFile = mStorage.createFile(SRC, srcPath, "text/plain", + "The five boxing wizards jump quickly".getBytes()); + + assertDstFileCountEquals(0); + + mStorage.simulateReadErrors(true); + + copyToDestination(Lists.newArrayList(testFile)); + + // 3 operations: file creation, writing, then deletion (due to failed copy). + mResolver.waitForChanges(3); + + assertDstFileCountEquals(0); + } + /** * Copies the given files to a pre-determined destination. * @@ -200,82 +275,55 @@ public class CopyTest extends ServiceTestCase<CopyService> { assertEquals("Incorrect file count after copy", expected, count); } - /** - * Verifies that the file pointed to by the given URI was correctly copied to the destination. - */ - private void assertCopied(Uri src) throws Exception { - Cursor cursor = null; - String srcName = null; - try { - cursor = mClient.query(src, null, null, null, null); - if (cursor.moveToFirst()) { - srcName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME); - } - } finally { - IoUtils.closeQuietly(cursor); - } - Uri dst = getDstFileUri(srcName); + private void assertCopied(String path) throws Exception { + File srcFile = mStorage.getFile(SRC, path); + File dstFile = mStorage.getFile(DST, path); + assertNotNull(dstFile); - InputStream in0 = null; - InputStream in1 = null; + FileInputStream src = null; + FileInputStream dst = null; try { - in0 = new ParcelFileDescriptor.AutoCloseInputStream(mClient.openFile(src, "r")); - in1 = new ParcelFileDescriptor.AutoCloseInputStream(mClient.openFile(dst, "r")); - - byte[] buffer0 = Streams.readFully(in0); - byte[] buffer1 = Streams.readFully(in1); - - MoreAsserts.assertEquals(buffer0, buffer1); - } finally { - IoUtils.closeQuietly(in0); - IoUtils.closeQuietly(in1); - } - } + src = new FileInputStream(srcFile); + dst = new FileInputStream(dstFile); + byte[] srcbuf = Streams.readFully(src); + byte[] dstbuf = Streams.readFully(dst); - /** - * Generates a file URI from a given filename. This assumes the file already exists in the - * destination root. - */ - private Uri getDstFileUri(String filename) throws RemoteException { - final Uri dstFileQuery = DocumentsContract.buildChildDocumentsUri(AUTHORITY, - mRoots.get(1).documentId); - Cursor cursor = null; - try { - // StubProvider doesn't seem to support query strings; filter the results manually. - cursor = mClient.query(dstFileQuery, null, null, null, null); - while (cursor.moveToNext()) { - if (filename.equals(getCursorString(cursor, Document.COLUMN_DISPLAY_NAME))) { - return DocumentsContract.buildDocumentUri(AUTHORITY, - getCursorString(cursor, Document.COLUMN_DOCUMENT_ID)); - } - } + MoreAsserts.assertEquals(srcbuf, dstbuf); } finally { - IoUtils.closeQuietly(cursor); + IoUtils.closeQuietly(src); + IoUtils.closeQuietly(dst); } - return null; } /** * Sets up a ContextWrapper that substitutes a stub NotificationManager. This allows the test to * listen for notification events, to gauge copy progress. + * + * @throws FileNotFoundException */ - private void setupTestContext() { - mContext = getSystemContext(); - System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath()); + private void setupTestContext() throws FileNotFoundException { + mSystemContext = getSystemContext(); - mNotificationManager = Mockito.spy((NotificationManager) mContext - .getSystemService(Context.NOTIFICATION_SERVICE)); - - // Insert a stub NotificationManager that enables us to listen for when copying is complete. - setContext(new ContextWrapper(mContext) { + // Set up the context with the test content resolver. + mResolver = new TestContentResolver(); + mContext = new ContextWrapper(mSystemContext) { @Override - public Object getSystemService(String name) { - if (Context.NOTIFICATION_SERVICE.equals(name)) { - return mNotificationManager; - } else { - return super.getSystemService(name); - } + public ContentResolver getContentResolver() { + return mResolver; } - }); + }; + setContext(mContext); + + // Create a local stub provider and add it to the content resolver. + ProviderInfo info = new ProviderInfo(); + info.authority = AUTHORITY; + info.exported = true; + info.grantUriPermissions = true; + info.readPermission = android.Manifest.permission.MANAGE_DOCUMENTS; + info.writePermission = android.Manifest.permission.MANAGE_DOCUMENTS; + + mStorage = new StubProvider(); + mStorage.attachInfo(mContext, info); + mResolver.addProvider(AUTHORITY, mStorage); } } diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java index 438f6cd..8cef433 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java @@ -21,9 +21,10 @@ import android.content.SharedPreferences; import android.content.pm.ProviderInfo; import android.content.res.AssetFileDescriptor; import android.database.Cursor; -import android.database.MatrixCursor.RowBuilder; import android.database.MatrixCursor; +import android.database.MatrixCursor.RowBuilder; import android.graphics.Point; +import android.net.Uri; import android.os.Bundle; import android.os.CancellationSignal; import android.os.FileUtils; @@ -32,15 +33,16 @@ import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; import android.provider.DocumentsContract.Root; import android.provider.DocumentsProvider; +import android.support.annotation.VisibleForTesting; import android.util.Log; import com.google.android.collect.Maps; import libcore.io.IoUtils; -import java.io.FileOutputStream; import java.io.File; import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -70,6 +72,7 @@ public class StubProvider extends DocumentsProvider { private String mAuthority; private SharedPreferences mPrefs; private Map<String, RootInfo> mRoots; + private boolean mSimulateReadErrors; @Override public void attachInfo(Context context, ProviderInfo info) { @@ -83,7 +86,8 @@ public class StubProvider extends DocumentsProvider { return true; } - private void clearCacheAndBuildRoots() { + @VisibleForTesting + public void clearCacheAndBuildRoots() { final File cacheDir = getContext().getCacheDir(); removeRecursively(cacheDir); mStorage.clear(); @@ -164,7 +168,7 @@ public class StubProvider extends DocumentsProvider { } else { try { if (!file.createNewFile()) { - throw new FileNotFoundException(); + throw new IllegalStateException("The file " + file.getPath() + " already exists"); } } catch (IOException e) { throw new FileNotFoundException(); @@ -173,6 +177,10 @@ public class StubProvider extends DocumentsProvider { final StubDocument document = new StubDocument(file, mimeType, parentDocument); notifyParentChanged(document.parentId); + getContext().getContentResolver().notifyChange( + DocumentsContract.buildDocumentUri(mAuthority, document.documentId), + null, false); + return document.documentId; } @@ -187,6 +195,9 @@ public class StubProvider extends DocumentsProvider { document.rootInfo.size -= fileSize; } notifyParentChanged(document.parentId); + getContext().getContentResolver().notifyChange( + DocumentsContract.buildDocumentUri(mAuthority, document.documentId), + null, false); } @Override @@ -226,7 +237,17 @@ public class StubProvider extends DocumentsProvider { throw new FileNotFoundException(); if ("r".equals(mode)) { - return ParcelFileDescriptor.open(document.file, ParcelFileDescriptor.MODE_READ_ONLY); + ParcelFileDescriptor pfd = ParcelFileDescriptor.open(document.file, + ParcelFileDescriptor.MODE_READ_ONLY); + if (mSimulateReadErrors) { + pfd = new ParcelFileDescriptor(pfd) { + @Override + public void checkError() throws IOException { + throw new IOException("Test error"); + } + }; + } + return pfd; } if ("w".equals(mode)) { return startWrite(document); @@ -235,6 +256,11 @@ public class StubProvider extends DocumentsProvider { throw new FileNotFoundException(); } + @VisibleForTesting + public void simulateReadErrors(boolean b) { + mSimulateReadErrors = b; + } + @Override public AssetFileDescriptor openDocumentThumbnail( String docId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException { @@ -281,11 +307,15 @@ public class StubProvider extends DocumentsProvider { } } } catch (IOException e) { + Log.e(TAG, "Error on close", e); closePipeWithErrorSilently(readPipe, e.getMessage()); } finally { IoUtils.closeQuietly(inputStream); IoUtils.closeQuietly(outputStream); notifyParentChanged(document.parentId); + getContext().getContentResolver().notifyChange( + DocumentsContract.buildDocumentUri(mAuthority, document.documentId), + null, false); } } }.start(); @@ -302,7 +332,6 @@ public class StubProvider extends DocumentsProvider { @Override public Bundle call(String method, String arg, Bundle extras) { - Log.d(TAG, "call: " + method + arg); switch (method) { case "clear": clearCacheAndBuildRoots(); @@ -376,30 +405,51 @@ public class StubProvider extends DocumentsProvider { } } - public File createFile(String rootId, File parent, String mimeType, String name) - throws IOException { - StubDocument parentDoc = null; + @VisibleForTesting + public Uri createFile(String rootId, String path, String mimeType, byte[] content) + throws FileNotFoundException, IOException { + StubDocument root = mRoots.get(rootId).rootDocument; + if (root == null) { + throw new FileNotFoundException("No roots with the ID " + rootId + " were found"); + } + File file = new File(root.file, path.substring(1)); + StubDocument parent = mStorage.get(getDocumentIdForFile(file.getParentFile())); if (parent == null) { - // Use the root dir as the parent, if one wasn't specified. - parentDoc = mRoots.get(rootId).rootDocument; - } else { - // Verify that the parent exists and is a directory. - parentDoc = mStorage.get(getDocumentIdForFile(parent)); - if (parentDoc == null) { - throw new IllegalArgumentException("Parent file not found."); + parent = mStorage.get(createFile(rootId, file.getParentFile().getPath(), + DocumentsContract.Document.MIME_TYPE_DIR, null)); + } + + if (DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType)) { + if (!file.mkdirs()) { + throw new FileNotFoundException("Couldn't create directory " + file.getPath()); } - if (!Document.MIME_TYPE_DIR.equals(parentDoc.mimeType)) { - throw new IllegalArgumentException("Parent file must be a directory."); + } else { + if (!file.createNewFile()) { + throw new FileNotFoundException("Couldn't create file " + file.getPath()); } + // Add content to the file. + FileOutputStream fout = new FileOutputStream(file); + fout.write(content); + fout.close(); } - File file = new File(parentDoc.file, name); - if (Document.MIME_TYPE_DIR.equals(mimeType)) { - file.mkdir(); - } else { - file.createNewFile(); + final StubDocument document = new StubDocument(file, mimeType, parent); + return DocumentsContract.buildDocumentUri(mAuthority, document.documentId); + } + + @VisibleForTesting + public File getFile(String rootId, String path) throws FileNotFoundException { + StubDocument root = mRoots.get(rootId).rootDocument; + if (root == null) { + throw new FileNotFoundException("No roots with the ID " + rootId + " were found"); + } + // Convert the path string into a path that's relative to the root. + File needle = new File(root.file, path.substring(1)); + + StubDocument found = mStorage.get(getDocumentIdForFile(needle)); + if (found == null) { + return null; } - new StubDocument(file, mimeType, parentDoc); - return file; + return found.file; } final class RootInfo { diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml index e060b4a..49ce427 100644 --- a/packages/Keyguard/res/values/strings.xml +++ b/packages/Keyguard/res/values/strings.xml @@ -96,8 +96,6 @@ <string name="keyguard_widget_24_hours_format" translatable="false">kk\uee01mm</string> <string name="keyguard_accessibility_pattern_unlock">Pattern unlock.</string> - <!-- Accessibility description of the face unlock. [CHAR_LIMIT=none] --> - <string name="keyguard_accessibility_face_unlock">Face unlock.</string> <!-- Accessibility description of the pin lock. [CHAR_LIMIT=none] --> <string name="keyguard_accessibility_pin_unlock">Pin unlock.</string> <!-- Accessibility description of the password lock. [CHAR_LIMIT=none] --> diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index c7b7628..d13d71c 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -58,7 +58,6 @@ import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; import android.hardware.fingerprint.FingerprintUtils; import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; -import android.service.trust.TrustAgentService; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener; @@ -154,6 +153,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private SubscriptionManager mSubscriptionManager; private List<SubscriptionInfo> mSubscriptionInfo; private boolean mFingerprintDetectionRunning; + private TrustManager mTrustManager; private final Handler mHandler = new Handler() { @Override @@ -550,7 +550,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { @Override public void onAuthenticationError(int errMsgId, CharSequence errString) { - mHandler.obtainMessage(MSG_FINGERPRINT_ERROR, errMsgId, 0, errString); + mHandler.obtainMessage(MSG_FINGERPRINT_ERROR, errMsgId, 0, errString).sendToTarget(); } }; private CancellationSignal mFingerprintCancelSignal; @@ -784,8 +784,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { e.printStackTrace(); } - TrustManager trustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE); - trustManager.registerTrustListener(this); + mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE); + mTrustManager.registerTrustListener(this); mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE); updateFingerprintListeningState(); @@ -801,7 +801,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { } private boolean shouldListenForFingerprint() { - return mScreenOn && mKeyguardIsVisible && !mSwitchingUser; + return mScreenOn && mKeyguardIsVisible && !mSwitchingUser + && mTrustManager.hasUserAuthenticatedSinceBoot(ActivityManager.getCurrentUser()); } private void startListeningForFingerprint() { diff --git a/packages/PrintSpooler/res/values/themes.xml b/packages/PrintSpooler/res/values/themes.xml index 532b01f..db319e9 100644 --- a/packages/PrintSpooler/res/values/themes.xml +++ b/packages/PrintSpooler/res/values/themes.xml @@ -16,10 +16,7 @@ <resources> - <style name="PrintActivity" parent="@android:style/Theme.Material"> - <item name="android:colorPrimary">@*android:color/material_blue_grey_900</item> - <item name="android:colorPrimaryDark">@*android:color/material_blue_grey_950</item> - <item name="android:colorAccent">@*android:color/material_deep_teal_500</item> + <style name="PrintActivity" parent="@android:style/Theme.Material.Settings"> <item name="android:windowIsTranslucent">true</item> <item name="android:windowBackground">@android:color/transparent</item> <item name="android:windowContentOverlay">@null</item> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index b2c9cd0..b702e35 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -64,6 +64,8 @@ <string name="wifi_not_in_range">Not in range</string> <!-- Summary for the remembered network but no internet connection was detected. --> <string name="wifi_no_internet">No Internet Access Detected, won\'t automatically reconnect.</string> + <!-- Summary for saved networks --> + <string name="saved_network">Saved by <xliff:g id="name">%1$s</xliff:g></string> <!-- Status message of Wi-Fi when it is connected by a Wi-Fi assistant application. [CHAR LIMIT=NONE] --> <string name="connected_via_wfa">Connected via Wi\u2011Fi assistant</string> @@ -71,6 +73,10 @@ <string name="connected_via_passpoint">Connected via %1$s</string> <!-- Status message of Wi-Fi when network has matching passpoint credentials. [CHAR LIMIT=NONE] --> <string name="available_via_passpoint">Available via %1$s</string> + <!-- Package name for Settings app--> + <string name="settings_package" translatable="false">com.android.settings</string> + <!-- Package name for Certinstaller app--> + <string name="certinstaller_package" translatable="false">com.android.certinstaller</string> <!-- Summary for Connected wifi network without internet --> <string name="wifi_connected_no_internet">Connected, no Internet</string> @@ -111,8 +117,10 @@ <string name="bluetooth_profile_pbap_summary">Use for contact sharing</string> <!-- Bluetooth settings. The user-visible string that is used whenever referring to the PAN profile (sharing this device's Internet connection). [CHAR LIMIT=40] --> <string name="bluetooth_profile_pan_nap">Internet connection sharing</string> - <!-- Bluetooth settings. The user-visible string that is used whenever referring to the map profile. --> + <!-- Bluetooth settings. The user-visible string that is used whenever referring to the map profile. --> <string name="bluetooth_profile_map">Message Access</string> + <!-- Bluetooth settings. The user-visible string that is used whenever referring to the SAP profile (sharing SIM card). --> + <string name="bluetooth_profile_sap">SIM Access</string> <!-- Bluetooth settings. Connection options screen. The summary for the A2DP checkbox preference when A2DP is connected. --> <string name="bluetooth_a2dp_profile_summary_connected">Connected to media audio</string> @@ -122,6 +130,8 @@ <string name="bluetooth_opp_profile_summary_connected">Connected to file transfer server</string> <!-- Bluetooth settings. Connection options screen. The summary for the map checkbox preference when map is connected. --> <string name="bluetooth_map_profile_summary_connected">Connected to map</string> + <!-- Bluetooth settings. Connection options screen. The summary for the sap checkbox preference when SAP is connected. --> + <string name="bluetooth_sap_profile_summary_connected">Connected to SAP</string> <!-- Bluetooth settings. Connection options screen. The summary for the OPP checkbox preference when OPP is not connected. --> <string name="bluetooth_opp_profile_summary_not_connected">Not connected to file transfer server</string> <!-- Bluetooth settings. Connection options screen. The summary for the HID checkbox preference when HID is connected. --> @@ -137,6 +147,8 @@ <string name="bluetooth_pan_profile_summary_use_for">Use for Internet access</string> <!-- Bluetooth settings. Connection options screen. The summary for the map checkbox preference that describes how checking it will set the map profile as preferred. --> <string name="bluetooth_map_profile_summary_use_for">Use for map</string> + <!-- Bluetooth settings. Connection options screen. The summary for the sap checkbox preference that describes how checking it will set the sap profile as preferred. --> + <string name="bluetooth_sap_profile_summary_use_for">Use for SIM access</string> <!-- Bluetooth settings. Connection options screen. The summary for the A2DP checkbox preference that describes how checking it will set the A2DP profile as preferred. --> <string name="bluetooth_a2dp_profile_summary_use_for">Use for media audio</string> <!-- Bluetooth settings. Connection options screen. The summary for the headset checkbox preference that describes how checking it will set the headset profile as preferred. --> diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index dd2368f..7534b8e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -67,10 +67,6 @@ public final class CachedBluetoothDevice implements Comparable<CachedBluetoothDe private boolean mVisible; - private int mPhonebookPermissionChoice; - - private int mMessagePermissionChoice; - private int mMessageRejectionCount; private final Collection<Callback> mCallbacks = new ArrayList<Callback>(); @@ -556,6 +552,7 @@ public final class CachedBluetoothDevice implements Comparable<CachedBluetoothDe mConnectAfterPairing = false; // cancel auto-connect setPhonebookPermissionChoice(ACCESS_UNKNOWN); setMessagePermissionChoice(ACCESS_UNKNOWN); + setSimPermissionChoice(ACCESS_UNKNOWN); mMessageRejectionCount = 0; saveMessageRejectionCount(); } @@ -732,6 +729,26 @@ public final class CachedBluetoothDevice implements Comparable<CachedBluetoothDe mDevice.setMessageAccessPermission(permission); } + public int getSimPermissionChoice() { + int permission = mDevice.getSimAccessPermission(); + if (permission == BluetoothDevice.ACCESS_ALLOWED) { + return ACCESS_ALLOWED; + } else if (permission == BluetoothDevice.ACCESS_REJECTED) { + return ACCESS_REJECTED; + } + return ACCESS_UNKNOWN; + } + + void setSimPermissionChoice(int permissionChoice) { + int permission = BluetoothDevice.ACCESS_UNKNOWN; + if (permissionChoice == ACCESS_ALLOWED) { + permission = BluetoothDevice.ACCESS_ALLOWED; + } else if (permissionChoice == ACCESS_REJECTED) { + permission = BluetoothDevice.ACCESS_REJECTED; + } + mDevice.setSimAccessPermission(permission); + } + // Migrates data from old data store (in Settings app's shared preferences) to new (in Bluetooth // app's shared preferences). private void migrateMessagePermissionChoice() { diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java new file mode 100644 index 0000000..25c53e6 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settingslib.bluetooth; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothClass; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothSap; +import android.bluetooth.BluetoothProfile; +import android.bluetooth.BluetoothUuid; +import android.content.Context; +import android.os.ParcelUuid; +import android.util.Log; + +import com.android.settingslib.R; + +import java.util.ArrayList; +import java.util.List; + +/** + * SapProfile handles Bluetooth SAP profile. + */ +final class SapProfile implements LocalBluetoothProfile { + private static final String TAG = "SapProfile"; + private static boolean V = true; + + private BluetoothSap mService; + private boolean mIsProfileReady; + + private final LocalBluetoothAdapter mLocalAdapter; + private final CachedBluetoothDeviceManager mDeviceManager; + private final LocalBluetoothProfileManager mProfileManager; + + static final ParcelUuid[] UUIDS = { + BluetoothUuid.SAP, + }; + + static final String NAME = "SAP"; + + // Order of this profile in device profiles list + private static final int ORDINAL = 10; + + // These callbacks run on the main thread. + private final class SapServiceListener + implements BluetoothProfile.ServiceListener { + + public void onServiceConnected(int profile, BluetoothProfile proxy) { + if (V) Log.d(TAG,"Bluetooth service connected"); + mService = (BluetoothSap) proxy; + // We just bound to the service, so refresh the UI for any connected SAP devices. + List<BluetoothDevice> deviceList = mService.getConnectedDevices(); + while (!deviceList.isEmpty()) { + BluetoothDevice nextDevice = deviceList.remove(0); + CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice); + // we may add a new device here, but generally this should not happen + if (device == null) { + Log.w(TAG, "SapProfile found new device: " + nextDevice); + device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice); + } + device.onProfileStateChanged(SapProfile.this, + BluetoothProfile.STATE_CONNECTED); + device.refresh(); + } + + mProfileManager.callServiceConnectedListeners(); + mIsProfileReady=true; + } + + public void onServiceDisconnected(int profile) { + if (V) Log.d(TAG,"Bluetooth service disconnected"); + mProfileManager.callServiceDisconnectedListeners(); + mIsProfileReady=false; + } + } + + public boolean isProfileReady() { + return mIsProfileReady; + } + + SapProfile(Context context, LocalBluetoothAdapter adapter, + CachedBluetoothDeviceManager deviceManager, + LocalBluetoothProfileManager profileManager) { + mLocalAdapter = adapter; + mDeviceManager = deviceManager; + mProfileManager = profileManager; + mLocalAdapter.getProfileProxy(context, new SapServiceListener(), + BluetoothProfile.SAP); + } + + public boolean isConnectable() { + return true; + } + + public boolean isAutoConnectable() { + return true; + } + + public boolean connect(BluetoothDevice device) { + if (mService == null) return false; + List<BluetoothDevice> sinks = mService.getConnectedDevices(); + if (sinks != null) { + for (BluetoothDevice sink : sinks) { + mService.disconnect(sink); + } + } + return mService.connect(device); + } + + public boolean disconnect(BluetoothDevice device) { + if (mService == null) return false; + List<BluetoothDevice> deviceList = mService.getConnectedDevices(); + if (!deviceList.isEmpty() && deviceList.get(0).equals(device)) { + if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) { + mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + } + return mService.disconnect(device); + } else { + return false; + } + } + + public int getConnectionStatus(BluetoothDevice device) { + if (mService == null) return BluetoothProfile.STATE_DISCONNECTED; + List<BluetoothDevice> deviceList = mService.getConnectedDevices(); + + return !deviceList.isEmpty() && deviceList.get(0).equals(device) + ? mService.getConnectionState(device) + : BluetoothProfile.STATE_DISCONNECTED; + } + + public boolean isPreferred(BluetoothDevice device) { + if (mService == null) return false; + return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF; + } + + public int getPreferred(BluetoothDevice device) { + if (mService == null) return BluetoothProfile.PRIORITY_OFF; + return mService.getPriority(device); + } + + public void setPreferred(BluetoothDevice device, boolean preferred) { + if (mService == null) return; + if (preferred) { + if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) { + mService.setPriority(device, BluetoothProfile.PRIORITY_ON); + } + } else { + mService.setPriority(device, BluetoothProfile.PRIORITY_OFF); + } + } + + public List<BluetoothDevice> getConnectedDevices() { + if (mService == null) return new ArrayList<BluetoothDevice>(0); + return mService.getDevicesMatchingConnectionStates( + new int[] {BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.STATE_CONNECTING, + BluetoothProfile.STATE_DISCONNECTING}); + } + + public String toString() { + return NAME; + } + + public int getOrdinal() { + return ORDINAL; + } + + public int getNameResource(BluetoothDevice device) { + return R.string.bluetooth_profile_sap; + } + + public int getSummaryResourceForDevice(BluetoothDevice device) { + int state = getConnectionStatus(device); + switch (state) { + case BluetoothProfile.STATE_DISCONNECTED: + return R.string.bluetooth_sap_profile_summary_use_for; + + case BluetoothProfile.STATE_CONNECTED: + return R.string.bluetooth_sap_profile_summary_connected; + + default: + return Utils.getConnectionStateSummary(state); + } + } + + public int getDrawableResource(BluetoothClass btClass) { + return R.drawable.ic_bt_cellphone; + } + + protected void finalize() { + if (V) Log.d(TAG, "finalize()"); + if (mService != null) { + try { + BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.SAP, + mService); + mService = null; + }catch (Throwable t) { + Log.w(TAG, "Error cleaning up SAP proxy", t); + } + } + } +} diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java index 1cf7248..c81f22a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java @@ -32,7 +32,6 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; -import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageVolume; @@ -349,6 +348,11 @@ public class StorageMeasurement { final Message finished = mMeasurementHandler.obtainMessage(MeasurementHandler.MSG_COMPLETED, details); + if (mVolume == null || !mVolume.isMountedReadable()) { + finished.sendToTarget(); + return; + } + if (mSharedVolume != null && mSharedVolume.isMountedReadable()) { final File basePath = mSharedVolume.getPathForUser(currentUser); @@ -375,8 +379,10 @@ public class StorageMeasurement { } final File file = mVolume.getPath(); - details.totalSize = file.getTotalSpace(); - details.availSize = file.getFreeSpace(); + if (file != null) { + details.totalSize = file.getTotalSpace(); + details.availSize = file.getFreeSpace(); + } // Measure all apps hosted on this volume for all users if (mVolume.getType() == VolumeInfo.TYPE_PRIVATE) { diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index 53e69e3..7eaa728 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -35,6 +35,12 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; import android.util.LruCache; +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; +import android.content.pm.PackageManager; +import android.os.UserHandle; +import android.os.RemoteException; +import android.app.AppGlobals; import com.android.settingslib.R; @@ -288,12 +294,28 @@ public class AccessPoint implements Comparable<AccessPoint> { } public String getSavedNetworkSummary() { - // Update to new summary - if (mConfig != null && mConfig.isPasspoint()) { - return ""; - } else { - return getSettingsSummary(); + if (mConfig != null) { + PackageManager pm = mContext.getPackageManager(); + String systemName = pm.getNameForUid(android.os.Process.SYSTEM_UID); + int userId = UserHandle.getUserId(mConfig.creatorUid); + ApplicationInfo appInfo = null; + if (mConfig.creatorName != null && mConfig.creatorName.equals(systemName)) { + appInfo = mContext.getApplicationInfo(); + } else { + try { + IPackageManager ipm = AppGlobals.getPackageManager(); + appInfo = ipm.getApplicationInfo(mConfig.creatorName, 0 /* flags */, userId); + } catch (RemoteException rex) { + } + } + if (appInfo != null && + !appInfo.packageName.equals(mContext.getString(R.string.settings_package)) && + !appInfo.packageName.equals( + mContext.getString(R.string.certinstaller_package))) { + return mContext.getString(R.string.saved_network, appInfo.loadLabel(pm)); + } } + return ""; } public String getSummary() { diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 5b4b4fd..dda9358 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -121,7 +121,7 @@ <activity android:name=".BugreportWarningActivity" - android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert" + android:theme="@*android:style/Theme.Material.DayNight.Dialog.Alert" android:finishOnCloseSystemDialogs="true" android:excludeFromRecents="true" android:exported="false" /> diff --git a/packages/SystemUI/res/drawable/ic_mic_26dp.xml b/packages/SystemUI/res/drawable/ic_mic_26dp.xml new file mode 100644 index 0000000..83e4ba8 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_mic_26dp.xml @@ -0,0 +1,24 @@ +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="26.0dp" + android:height="26.0dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:pathData="M12.000000,14.000000c1.700000,0.000000 3.000000,-1.300000 3.000000,-3.000000l0.000000,-6.000000c0.000000,-1.700000 -1.300000,-3.000000 -3.000000,-3.000000c-1.700000,0.000000 -3.000000,1.300000 -3.000000,3.000000l0.000000,6.000000C9.000000,12.700000 10.300000,14.000000 12.000000,14.000000zM17.299999,11.000000c0.000000,3.000000 -2.500000,5.100000 -5.300000,5.100000c-2.800000,0.000000 -5.300000,-2.100000 -5.300000,-5.100000L5.000000,11.000000c0.000000,3.400000 2.700000,6.200000 6.000000,6.700000L11.000000,21.000000l2.000000,0.000000l0.000000,-3.300000c3.300000,-0.500000 6.000000,-3.300000 6.000000,-6.700000L17.299999,11.000001z" + android:fillColor="#FF000000"/> +</vector> diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index 1057464..5d0367e 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -52,7 +52,7 @@ android:contentDescription="@string/accessibility_camera_button" /> <com.android.systemui.statusbar.KeyguardAffordanceView - android:id="@+id/phone_button" + android:id="@+id/left_button" android:layout_height="@dimen/keyguard_affordance_height" android:layout_width="@dimen/keyguard_affordance_width" android:layout_gravity="bottom|start" diff --git a/packages/SystemUI/res/layout/zen_mode_panel.xml b/packages/SystemUI/res/layout/zen_mode_panel.xml index 595c9ed..0264f3d 100644 --- a/packages/SystemUI/res/layout/zen_mode_panel.xml +++ b/packages/SystemUI/res/layout/zen_mode_panel.xml @@ -52,7 +52,7 @@ android:layout_alignParentEnd="true" android:background="@drawable/btn_borderless_rect" android:clickable="true" - android:contentDescription="@string/accessibility_desc_confirm" + android:contentDescription="@string/accessibility_desc_close" android:scaleType="center" android:src="@drawable/ic_close" android:tint="@android:color/white" /> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 80fecac..8606a59 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -205,6 +205,8 @@ <string name="accessibility_camera_button">Camera</string> <!-- Content description of the phone button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_phone_button">Phone</string> + <!-- Content description of the phone button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> + <string name="accessibility_voice_assist_button">Voice Assist</string> <!-- Content description of the unlock button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_unlock_button">Unlock</string> <!-- Click action label for accessibility for the unlock button. [CHAR LIMIT=NONE] --> @@ -212,6 +214,8 @@ <!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] --> <string name="phone_label">open phone</string> <!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] --> + <string name="voice_assist_label">open voice assist</string> + <!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] --> <string name="camera_label">open camera</string> <!-- Caption for "Recents resize" developer debug feature. [CHAR LIMIT=NONE] --> <string name="recents_caption_resize">Select new task layout</string> @@ -420,8 +424,8 @@ <string name="accessibility_desc_settings">Settings</string> <!-- Content description for the recent apps panel (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_desc_recent_apps">Overview.</string> - <!-- Content description for the confirm button in the zen mode panel introduction message. [CHAR LIMIT=NONE] --> - <string name="accessibility_desc_confirm">Confirm</string> + <!-- Content description for the close button in the zen mode panel introduction message. [CHAR LIMIT=NONE] --> + <string name="accessibility_desc_close">Close</string> <!-- Content description of the user tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_quick_settings_user">User <xliff:g id="user" example="John Doe">%s</xliff:g>.</string> @@ -753,11 +757,14 @@ <!-- Shows when people have pressed the unlock icon to explain how to unlock. [CHAR LIMIT=60] --> <string name="keyguard_unlock">Swipe up to unlock</string> - <!-- Shows when people have clicked at the left edge of the screen to explain how to open the phone. In right-to-left languages, this is the opposite direction. [CHAR LIMIT=60] --> - <string name="phone_hint">Swipe right for phone</string> + <!-- Shows when people have clicked on the phone icon [CHAR LIMIT=60] --> + <string name="phone_hint">Swipe from icon for phone</string> + + <!-- Shows when people have clicked on the voice assist icon [CHAR LIMIT=60] --> + <string name="voice_hint">Swipe from icon for voice assist</string> - <!-- Shows when people have clicked at the right edge of the screen to explain how to open the phone. In right-to-left languages, this is the opposite direction. [CHAR LIMIT=60] --> - <string name="camera_hint">Swipe left for camera</string> + <!-- Shows when people have clicked on the camera icon [CHAR LIMIT=60] --> + <string name="camera_hint">Swipe from icon for camera</string> <!-- Interruption level: None. [CHAR LIMIT=40] --> <string name="interruption_level_none">Total silence</string> @@ -951,6 +958,12 @@ <!-- Button label for ending zen mode in the volume dialog --> <string name="volume_zen_end_now">End now</string> + <!-- Content description for accessibility (not shown on the screen): volume dialog expand button. [CHAR LIMIT=NONE] --> + <string name="accessibility_volume_expand">Expand</string> + + <!-- Content description for accessibility (not shown on the screen): volume dialog collapse button. [CHAR LIMIT=NONE] --> + <string name="accessibility_volume_collapse">Collapse</string> + <!-- Screen pinning dialog title. --> <string name="screen_pinning_title">Screen is pinned</string> <!-- Screen pinning dialog description. --> diff --git a/packages/SystemUI/src/com/android/systemui/EventLogConstants.java b/packages/SystemUI/src/com/android/systemui/EventLogConstants.java index c8af2d4..43a1be1 100644 --- a/packages/SystemUI/src/com/android/systemui/EventLogConstants.java +++ b/packages/SystemUI/src/com/android/systemui/EventLogConstants.java @@ -34,4 +34,10 @@ public class EventLogConstants { public static final int SYSUI_LOCKSCREEN_GESTURE_TAP_LOCK = 6; /** The user tapped a notification, needs to tap again to launch. */ public static final int SYSUI_LOCKSCREEN_GESTURE_TAP_NOTIFICATION_ACTIVATE = 7; + /** The user swiped down to open quick settings, from keyguard. */ + public static final int SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_QS = 8; + /** The user swiped down to open quick settings, from shade. */ + public static final int SYSUI_SHADE_GESTURE_SWIPE_DOWN_QS = 9; + /** The user tapped on the status bar to open quick settings, from shade. */ + public static final int SYSUI_TAP_TO_OPEN_QS = 10; } diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistGestureManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java index d9f2324..d1f8963 100644 --- a/packages/SystemUI/src/com/android/systemui/assist/AssistGestureManager.java +++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java @@ -33,11 +33,11 @@ import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.PhoneStatusBar; /** - * Class to manage everything around the assist gesture. + * Class to manage everything related to assist in SystemUI. */ -public class AssistGestureManager { +public class AssistManager { - private static final String TAG = "AssistGestureManager"; + private static final String TAG = "AssistManager"; private static final String ASSIST_ICON_METADATA_NAME = "com.android.systemui.action_assist_icon"; @@ -77,7 +77,7 @@ public class AssistGestureManager { } }; - public AssistGestureManager(PhoneStatusBar bar, Context context) { + public AssistManager(PhoneStatusBar bar, Context context) { mContext = context; mBar = bar; mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); @@ -194,6 +194,14 @@ public class AssistGestureManager { } } + public void launchVoiceAssistFromKeyguard() { + try { + mVoiceInteractionManagerService.launchVoiceAssistFromKeyguard(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to call launchVoiceAssistFromKeyguard", e); + } + } + private boolean getVoiceInteractorSupportsAssistGesture() { try { return mVoiceInteractionManagerService.activeServiceSupportsAssist(); @@ -203,7 +211,16 @@ public class AssistGestureManager { } } - private ComponentName getVoiceInteractorComponentName() { + public boolean canVoiceAssistBeLaunchedFromKeyguard() { + try { + return mVoiceInteractionManagerService.activeServiceSupportsLaunchFromKeyguard(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to call activeServiceSupportsLaunchFromKeyguard", e); + return false; + } + } + + public ComponentName getVoiceInteractorComponentName() { try { return mVoiceInteractionManagerService.getActiveServiceComponentName(); } catch (RemoteException e) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 1001feb..ad97f91 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -39,7 +39,6 @@ import com.android.systemui.R; import com.android.systemui.recents.misc.DebugTrigger; import com.android.systemui.recents.misc.ReferenceCountedTrigger; import com.android.systemui.recents.misc.SystemServicesProxy; -import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.RecentsTaskLoadPlan; import com.android.systemui.recents.model.RecentsTaskLoader; import com.android.systemui.recents.model.Task; @@ -392,15 +391,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED); registerReceiver(mSystemBroadcastReceiver, filter); - - // Private API calls to make the shadows look better - try { - Utilities.setShadowProperty("ambientRatio", String.valueOf(1.5f)); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } } /** Inflates the debug overlay if debug mode is enabled. */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java index 84544ff..e810410 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java @@ -22,27 +22,11 @@ import android.graphics.Matrix; import android.graphics.Rect; import android.view.View; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.ArrayList; /* Common code */ public class Utilities { - // Reflection methods for altering shadows - private static Method sPropertyMethod; - static { - try { - Class<?> c = Class.forName("android.view.DisplayListCanvas"); - sPropertyMethod = c.getDeclaredMethod("setProperty", String.class, String.class); - if (!sPropertyMethod.isAccessible()) sPropertyMethod.setAccessible(true); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } - } - /** Scales a rect about its centroid */ public static void scaleRectAboutCenter(Rect r, float scale) { if (scale != 1.0f) { @@ -163,12 +147,6 @@ public class Utilities { (1f - overlayAlpha) * Color.blue(overlayColor))); } - /** Sets some private shadow properties. */ - public static void setShadowProperty(String property, String value) - throws IllegalAccessException, InvocationTargetException { - sPropertyMethod.invoke(null, property, value); - } - /** * Cancels an animation ensuring that if it has listeners, onCancel and onEnd * are not called. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java index e632cc8..17e2cb5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java @@ -59,13 +59,6 @@ public abstract class ExpandableView extends FrameLayout { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int ownMaxHeight = mMaxViewHeight; - int heightMode = MeasureSpec.getMode(heightMeasureSpec); - boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY; - boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST; - if (hasFixedHeight || isHeightLimited) { - int size = MeasureSpec.getSize(heightMeasureSpec); - ownMaxHeight = Math.min(ownMaxHeight, size); - } int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST); int maxChildHeight = 0; int childCount = getChildCount(); @@ -92,8 +85,7 @@ public abstract class ExpandableView extends FrameLayout { mMatchParentViews.add(child); } } - int ownHeight = hasFixedHeight ? ownMaxHeight : - isHeightLimited ? Math.min(ownMaxHeight, maxChildHeight) : maxChildHeight; + int ownHeight = Math.min(ownMaxHeight, maxChildHeight); newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY); for (View child : mMatchParentViews) { child.measure(getChildMeasureSpec( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java index 23810f9..ee5eb38 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ActivityStarter.java @@ -25,4 +25,5 @@ import android.content.Intent; */ public interface ActivityStarter { public void startActivity(Intent intent, boolean dismissShade); + void preventNextAnimation(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java index 8343497..8bffdc9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java @@ -131,6 +131,10 @@ public class KeyguardAffordanceHelper { mCenterIcon = mCallback.getCenterIcon(); mRightIcon = mCallback.getRightIcon(); mRightIcon.setIsLeft(false); + updatePreviews(); + } + + public void updatePreviews() { mLeftIcon.setPreviewView(mCallback.getLeftPreview()); mRightIcon.setPreviewView(mCallback.getRightPreview()); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index fabc1a6..efc3ea0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -25,17 +25,13 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; -import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.graphics.drawable.InsetDrawable; -import android.hardware.fingerprint.FingerprintManager; import android.os.AsyncTask; import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; -import android.os.Vibrator; import android.provider.MediaStore; -import android.provider.Settings; import android.telecom.TelecomManager; import android.util.AttributeSet; import android.util.Log; @@ -54,6 +50,7 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.EventLogConstants; import com.android.systemui.EventLogTags; import com.android.systemui.R; +import com.android.systemui.assist.AssistManager; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardAffordanceView; import com.android.systemui.statusbar.KeyguardIndicationController; @@ -85,12 +82,12 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private static final long TRANSIENT_FP_ERROR_TIMEOUT = 1300; private KeyguardAffordanceView mCameraImageView; - private KeyguardAffordanceView mPhoneImageView; + private KeyguardAffordanceView mLeftAffordanceView; private LockIcon mLockIcon; private TextView mIndicationText; private ViewGroup mPreviewContainer; - private View mPhonePreview; + private View mLeftPreview; private View mCameraPreview; private ActivityStarter mActivityStarter; @@ -104,6 +101,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private final Interpolator mLinearOutSlowInInterpolator; private boolean mPrewarmSent; + private boolean mLeftIsVoiceAssist; + private AssistManager mAssistManager; public KeyguardBottomAreaView(Context context) { this(context, null); @@ -133,8 +132,12 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL label = getResources().getString(R.string.unlock_label); } else if (host == mCameraImageView) { label = getResources().getString(R.string.camera_label); - } else if (host == mPhoneImageView) { - label = getResources().getString(R.string.phone_label); + } else if (host == mLeftAffordanceView) { + if (mLeftIsVoiceAssist) { + label = getResources().getString(R.string.voice_assist_label); + } else { + label = getResources().getString(R.string.phone_label); + } } info.addAction(new AccessibilityAction(ACTION_CLICK, label)); } @@ -149,8 +152,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } else if (host == mCameraImageView) { launchCamera(); return true; - } else if (host == mPhoneImageView) { - launchPhone(); + } else if (host == mLeftAffordanceView) { + launchLeftAffordance(); return true; } } @@ -164,29 +167,28 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mLockPatternUtils = new LockPatternUtils(mContext); mPreviewContainer = (ViewGroup) findViewById(R.id.preview_container); mCameraImageView = (KeyguardAffordanceView) findViewById(R.id.camera_button); - mPhoneImageView = (KeyguardAffordanceView) findViewById(R.id.phone_button); + mLeftAffordanceView = (KeyguardAffordanceView) findViewById(R.id.left_button); mLockIcon = (LockIcon) findViewById(R.id.lock_icon); mIndicationText = (TextView) findViewById(R.id.keyguard_indication_text); watchForCameraPolicyChanges(); updateCameraVisibility(); - updatePhoneVisibility(); mUnlockMethodCache = UnlockMethodCache.getInstance(getContext()); mUnlockMethodCache.addListener(this); mLockIcon.update(); setClipChildren(false); setClipToPadding(false); mPreviewInflater = new PreviewInflater(mContext, new LockPatternUtils(mContext)); - inflatePreviews(); + inflateCameraPreview(); mLockIcon.setOnClickListener(this); mLockIcon.setOnLongClickListener(this); mCameraImageView.setOnClickListener(this); - mPhoneImageView.setOnClickListener(this); + mLeftAffordanceView.setOnClickListener(this); initAccessibility(); } private void initAccessibility() { mLockIcon.setAccessibilityDelegate(mAccessibilityDelegate); - mPhoneImageView.setAccessibilityDelegate(mAccessibilityDelegate); + mLeftAffordanceView.setAccessibilityDelegate(mAccessibilityDelegate); mCameraImageView.setAccessibilityDelegate(mAccessibilityDelegate); } @@ -247,9 +249,26 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mCameraImageView.setVisibility(visible ? View.VISIBLE : View.GONE); } - private void updatePhoneVisibility() { - boolean visible = isPhoneVisible(); - mPhoneImageView.setVisibility(visible ? View.VISIBLE : View.GONE); + private void updateLeftAffordanceIcon() { + mLeftIsVoiceAssist = canLaunchVoiceAssist(); + int drawableId; + int contentDescription; + if (mLeftIsVoiceAssist) { + mLeftAffordanceView.setVisibility(View.VISIBLE); + drawableId = R.drawable.ic_mic_26dp; + contentDescription = R.string.accessibility_voice_assist_button; + } else { + boolean visible = isPhoneVisible(); + mLeftAffordanceView.setVisibility(visible ? View.VISIBLE : View.GONE); + drawableId = R.drawable.ic_phone_24dp; + contentDescription = R.string.accessibility_phone_button; + } + mLeftAffordanceView.setImageDrawable(mContext.getDrawable(drawableId)); + mLeftAffordanceView.setContentDescription(mContext.getString(contentDescription)); + } + + public boolean isLeftVoiceAssist() { + return mLeftIsVoiceAssist; } private boolean isPhoneVisible() { @@ -287,9 +306,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL @Override public void onStateChanged(boolean accessibilityEnabled, boolean touchExplorationEnabled) { mCameraImageView.setClickable(touchExplorationEnabled); - mPhoneImageView.setClickable(touchExplorationEnabled); + mLeftAffordanceView.setClickable(touchExplorationEnabled); mCameraImageView.setFocusable(accessibilityEnabled); - mPhoneImageView.setFocusable(accessibilityEnabled); + mLeftAffordanceView.setFocusable(accessibilityEnabled); mLockIcon.update(); } @@ -297,8 +316,8 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public void onClick(View v) { if (v == mCameraImageView) { launchCamera(); - } else if (v == mPhoneImageView) { - launchPhone(); + } else if (v == mLeftAffordanceView) { + launchLeftAffordance(); } if (v == mLockIcon) { if (!mAccessibilityController.isAccessibilityEnabled()) { handleTrustCircleClick(); @@ -363,6 +382,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL @Override public void run() { mContext.startActivityAsUser(intent, UserHandle.CURRENT); + mActivityStarter.preventNextAnimation(); } }); } else { @@ -373,7 +393,35 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } } - public void launchPhone() { + public void launchLeftAffordance() { + if (mLeftIsVoiceAssist) { + launchVoiceAssist(); + } else { + launchPhone(); + } + } + + private void launchVoiceAssist() { + Runnable runnable = new Runnable() { + @Override + public void run() { + mAssistManager.launchVoiceAssistFromKeyguard(); + mActivityStarter.preventNextAnimation(); + } + }; + if (mPhoneStatusBar.isKeyguardCurrentlySecure()) { + AsyncTask.execute(runnable); + } else { + mPhoneStatusBar.executeRunnableDismissingKeyguard(runnable, false /* dismissShade */, + false /* afterKeyguardGone */); + } + } + + private boolean canLaunchVoiceAssist() { + return mAssistManager.canVoiceAssistBeLaunchedFromKeyguard(); + } + + private void launchPhone() { final TelecomManager tm = TelecomManager.from(mContext); if (tm.isInCall()) { AsyncTask.execute(new Runnable() { @@ -397,19 +445,19 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } } - public KeyguardAffordanceView getPhoneView() { - return mPhoneImageView; + public KeyguardAffordanceView getLeftView() { + return mLeftAffordanceView; } - public KeyguardAffordanceView getCameraView() { + public KeyguardAffordanceView getRightView() { return mCameraImageView; } - public View getPhonePreview() { - return mPhonePreview; + public View getLeftPreview() { + return mLeftPreview; } - public View getCameraPreview() { + public View getRightPreview() { return mCameraPreview; } @@ -432,23 +480,35 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL updateCameraVisibility(); } - private void inflatePreviews() { - mPhonePreview = mPreviewInflater.inflatePreview(PHONE_INTENT); + private void inflateCameraPreview() { mCameraPreview = mPreviewInflater.inflatePreview(getCameraIntent()); - if (mPhonePreview != null) { - mPreviewContainer.addView(mPhonePreview); - mPhonePreview.setVisibility(View.INVISIBLE); - } if (mCameraPreview != null) { mPreviewContainer.addView(mCameraPreview); mCameraPreview.setVisibility(View.INVISIBLE); } } + private void updateLeftPreview() { + View previewBefore = mLeftPreview; + if (previewBefore != null) { + mPreviewContainer.removeView(previewBefore); + } + if (mLeftIsVoiceAssist) { + mLeftPreview = mPreviewInflater.inflatePreviewFromService( + mAssistManager.getVoiceInteractorComponentName()); + } else { + mLeftPreview = mPreviewInflater.inflatePreview(PHONE_INTENT); + } + if (mLeftPreview != null) { + mPreviewContainer.addView(mLeftPreview); + mLeftPreview.setVisibility(View.INVISIBLE); + } + } + public void startFinishDozeAnimation() { long delay = 0; - if (mPhoneImageView.getVisibility() == View.VISIBLE) { - startFinishDozeAnimationElement(mPhoneImageView, delay); + if (mLeftAffordanceView.getVisibility() == View.VISIBLE) { + startFinishDozeAnimationElement(mLeftAffordanceView, delay); delay += DOZE_ANIMATION_STAGGER_DELAY; } startFinishDozeAnimationElement(mLockIcon, delay); @@ -543,4 +603,14 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL KeyguardIndicationController keyguardIndicationController) { mIndicationController = keyguardIndicationController; } + + public void setAssistManager(AssistManager assistManager) { + mAssistManager = assistManager; + updateLeftAffordance(); + } + + public void updateLeftAffordance() { + updateLeftAffordanceIcon(); + updateLeftPreview(); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index a8ecc42..f77ac4b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -39,6 +39,7 @@ import android.view.animation.Interpolator; import android.widget.FrameLayout; import android.widget.TextView; +import com.android.internal.logging.MetricsLogger; import com.android.keyguard.KeyguardStatusView; import com.android.systemui.EventLogConstants; import com.android.systemui.EventLogTags; @@ -73,6 +74,10 @@ public class NotificationPanelView extends PanelView implements private static final float HEADER_RUBBERBAND_FACTOR = 2.05f; private static final float LOCK_ICON_ACTIVE_SCALE = 1.2f; + private static final String COUNTER_PANEL_OPEN = "panel_open"; + private static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs"; + private static final String COUNTER_PANEL_OPEN_PEEK = "panel_open_peek"; + public static final long DOZE_ANIMATION_DURATION = 700; private KeyguardAffordanceHelper mAfforanceHelper; @@ -541,6 +546,8 @@ public class NotificationPanelView extends PanelView implements initDownStates(event); if (mHeadsUpTouchHelper.onInterceptTouchEvent(event)) { mIsExpansionFromHeadsUp = true; + MetricsLogger.count(mContext, COUNTER_PANEL_OPEN, 1); + MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_PEEK, 1); return true; } if (!isFullyCollapsed() && onQsIntercept(event)) { @@ -617,7 +624,7 @@ public class NotificationPanelView extends PanelView implements case MotionEvent.ACTION_UP: trackMovement(event); if (mQsTracking) { - flingQsWithCurrentVelocity( + flingQsWithCurrentVelocity(y, event.getActionMasked() == MotionEvent.ACTION_CANCEL); mQsTracking = false; } @@ -655,9 +662,24 @@ public class NotificationPanelView extends PanelView implements super.requestDisallowInterceptTouchEvent(disallowIntercept); } - private void flingQsWithCurrentVelocity(boolean isCancelMotionEvent) { + private void flingQsWithCurrentVelocity(float y, boolean isCancelMotionEvent) { + float vel = getCurrentVelocity(); + final boolean expandsQs = flingExpandsQs(vel); + if (expandsQs) { + logQsSwipeDown(y); + } + flingSettings(vel, expandsQs && !isCancelMotionEvent); + } + + private void logQsSwipeDown(float y) { float vel = getCurrentVelocity(); - flingSettings(vel, flingExpandsQs(vel) && !isCancelMotionEvent); + final int gesture = mStatusBarState == StatusBarState.KEYGUARD + ? EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_QS + : EventLogConstants.SYSUI_SHADE_GESTURE_SWIPE_DOWN_QS; + EventLogTags.writeSysuiLockscreenGesture( + gesture, + (int) ((y - mInitialTouchY) / mStatusBar.getDisplayDensity()), + (int) (vel / mStatusBar.getDisplayDensity())); } private boolean flingExpandsQs(float vel) { @@ -699,6 +721,7 @@ public class NotificationPanelView extends PanelView implements return true; } if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isFullyCollapsed()) { + MetricsLogger.count(mContext, COUNTER_PANEL_OPEN, 1); updateVerticalPanelPosition(event.getX()); } super.onTouchEvent(event); @@ -738,6 +761,7 @@ public class NotificationPanelView extends PanelView implements if (mTwoFingerQsExpandPossible && event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN && event.getPointerCount() == 2 && event.getY(event.getActionIndex()) < mStatusBarMinHeight) { + MetricsLogger.count(mContext, COUNTER_PANEL_OPEN_QS, 1); mQsExpandImmediate = true; requestPanelHeightUpdate(); @@ -799,6 +823,7 @@ public class NotificationPanelView extends PanelView implements } final float y = event.getY(pointerIndex); final float x = event.getX(pointerIndex); + final float h = y - mInitialTouchY; switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: @@ -826,7 +851,6 @@ public class NotificationPanelView extends PanelView implements break; case MotionEvent.ACTION_MOVE: - final float h = y - mInitialTouchY; setQsExpansion(h + mInitialHeightOnTouch); if (h >= getFalsingThreshold()) { mQsTouchAboveFalsingThreshold = true; @@ -842,9 +866,10 @@ public class NotificationPanelView extends PanelView implements float fraction = getQsExpansionFraction(); if ((fraction != 0f || y >= mInitialTouchY) && (fraction != 1f || y <= mInitialTouchY)) { - flingQsWithCurrentVelocity( + flingQsWithCurrentVelocity(y, event.getActionMasked() == MotionEvent.ACTION_CANCEL); } else { + logQsSwipeDown(y); mScrollYOverride = -1; } if (mVelocityTracker != null) { @@ -952,6 +977,10 @@ public class NotificationPanelView extends PanelView implements } else { mKeyguardStatusBar.setAlpha(1f); mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE); + if (keyguardShowing && oldState != mStatusBarState) { + mKeyguardBottomArea.updateLeftAffordance(); + mAfforanceHelper.updatePreviews(); + } } resetVerticalPanelPosition(); updateQsState(); @@ -1815,6 +1844,9 @@ public class NotificationPanelView extends PanelView implements if (mQsExpanded) { flingSettings(0 /* vel */, false /* expand */); } else if (mQsExpansionEnabled) { + EventLogTags.writeSysuiLockscreenGesture( + EventLogConstants.SYSUI_TAP_TO_OPEN_QS, + 0, 0); flingSettings(0 /* vel */, true /* expand */); } } @@ -1831,7 +1863,7 @@ public class NotificationPanelView extends PanelView implements if (start) { EventLogTags.writeSysuiLockscreenGesture( EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DIALER, lengthDp, velocityDp); - mKeyguardBottomArea.launchPhone(); + mKeyguardBottomArea.launchLeftAffordance(); } else { EventLogTags.writeSysuiLockscreenGesture( EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA, lengthDp, velocityDp); @@ -1912,15 +1944,19 @@ public class NotificationPanelView extends PanelView implements if (rightIcon) { mStatusBar.onCameraHintStarted(); } else { - mStatusBar.onPhoneHintStarted(); + if (mKeyguardBottomArea.isLeftVoiceAssist()) { + mStatusBar.onVoiceAssistHintStarted(); + } else { + mStatusBar.onPhoneHintStarted(); + } } } @Override public KeyguardAffordanceView getLeftIcon() { return getLayoutDirection() == LAYOUT_DIRECTION_RTL - ? mKeyguardBottomArea.getCameraView() - : mKeyguardBottomArea.getPhoneView(); + ? mKeyguardBottomArea.getRightView() + : mKeyguardBottomArea.getLeftView(); } @Override @@ -1931,22 +1967,22 @@ public class NotificationPanelView extends PanelView implements @Override public KeyguardAffordanceView getRightIcon() { return getLayoutDirection() == LAYOUT_DIRECTION_RTL - ? mKeyguardBottomArea.getPhoneView() - : mKeyguardBottomArea.getCameraView(); + ? mKeyguardBottomArea.getLeftView() + : mKeyguardBottomArea.getRightView(); } @Override public View getLeftPreview() { return getLayoutDirection() == LAYOUT_DIRECTION_RTL - ? mKeyguardBottomArea.getCameraPreview() - : mKeyguardBottomArea.getPhonePreview(); + ? mKeyguardBottomArea.getRightPreview() + : mKeyguardBottomArea.getLeftPreview(); } @Override public View getRightPreview() { return getLayoutDirection() == LAYOUT_DIRECTION_RTL - ? mKeyguardBottomArea.getPhonePreview() - : mKeyguardBottomArea.getCameraPreview(); + ? mKeyguardBottomArea.getLeftPreview() + : mKeyguardBottomArea.getRightPreview(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java index f3d4c7f..d5209ea 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -80,6 +80,14 @@ public class PanelBar extends FrameLayout { } } + public void setBouncerShowing(boolean showing) { + if (mPanelHolder != null) { + mPanelHolder.setImportantForAccessibility( + showing ? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS + : IMPORTANT_FOR_ACCESSIBILITY_AUTO); + } + } + public float getBarHeight() { return getMeasuredHeight(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 85f312c..38812ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -46,6 +46,7 @@ import java.io.PrintWriter; public abstract class PanelView extends FrameLayout { public static final boolean DEBUG = PanelBar.DEBUG; public static final String TAG = PanelView.class.getSimpleName(); + private final void logf(String fmt, Object... args) { Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args)); } @@ -77,6 +78,7 @@ public abstract class PanelView extends FrameLayout { private boolean mTouchStartedInEmptyArea; private boolean mMotionAborted; private boolean mUpwardsWhenTresholdReached; + private boolean mAnimatingOnDown; private ValueAnimator mHeightAnimator; private ObjectAnimator mPeekAnimator; @@ -459,8 +461,8 @@ public abstract class PanelView extends FrameLayout { switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: mStatusBar.userActivity(); - if (mHeightAnimator != null && !mHintAnimationRunning || - mPeekPending || mPeekAnimator != null) { + mAnimatingOnDown = mHeightAnimator != null; + if (mAnimatingOnDown && mClosing && !mHintAnimationRunning || mPeekPending || mPeekAnimator != null) { cancelHeightAnimator(); cancelPeek(); mTouchSlopExceeded = true; @@ -501,8 +503,10 @@ public abstract class PanelView extends FrameLayout { case MotionEvent.ACTION_MOVE: final float h = y - mInitialTouchY; trackMovement(event); - if (scrolledToBottom || mTouchStartedInEmptyArea) { - if (h < -mTouchSlop && h < -Math.abs(x - mInitialTouchX)) { + if (scrolledToBottom || mTouchStartedInEmptyArea || mAnimatingOnDown) { + float hAbs = Math.abs(h); + if ((h < -mTouchSlop || (mAnimatingOnDown && hAbs > mTouchSlop)) + && hAbs > Math.abs(x - mInitialTouchX)) { cancelHeightAnimator(); startExpandMotion(x, y, true /* startTracking */, mExpandedHeight); return true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 1c46d42..351977b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -76,6 +76,7 @@ import android.view.Display; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.MotionEvent; +import android.view.ThreadedRenderer; import android.view.VelocityTracker; import android.view.View; import android.view.ViewGroup.LayoutParams; @@ -101,7 +102,7 @@ import com.android.systemui.EventLogConstants; import com.android.systemui.EventLogTags; import com.android.systemui.Prefs; import com.android.systemui.R; -import com.android.systemui.assist.AssistGestureManager; +import com.android.systemui.assist.AssistManager; import com.android.systemui.doze.DozeHost; import com.android.systemui.doze.DozeLog; import com.android.systemui.keyguard.KeyguardViewMediator; @@ -323,7 +324,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private int mNavigationIconHints = 0; private HandlerThread mHandlerThread; - private AssistGestureManager mAssistGestureManager; + private AssistManager mAssistManager; // ensure quick settings is disabled until the current user makes it through the setup wizard private boolean mUserSetup = false; @@ -645,8 +646,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, new NavigationBarView.OnVerticalChangedListener() { @Override public void onVerticalChanged(boolean isVertical) { - if (mAssistGestureManager != null) { - mAssistGestureManager.onConfigurationChanged(); + if (mAssistManager != null) { + mAssistManager.onConfigurationChanged(); } mNotificationPanel.setQsScrimEnabled(!isVertical); } @@ -662,6 +663,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // no window manager? good luck with that } + mAssistManager = new AssistManager(this, context); + // figure out which pixel-format to use for the status bar. mPixelFormat = PixelFormat.OPAQUE; @@ -720,6 +723,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mKeyguardBottomArea = (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area); mKeyguardBottomArea.setActivityStarter(this); + mKeyguardBottomArea.setAssistManager(mAssistManager); mKeyguardIndicationController = new KeyguardIndicationController(mContext, (KeyguardIndicationTextView) mStatusBarWindow.findViewById( R.id.keyguard_indication_text)); @@ -841,7 +845,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mBroadcastReceiver.onReceive(mContext, new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF)); - mAssistGestureManager = new AssistGestureManager(this, context); // receive broadcasts IntentFilter filter = new IntentFilter(); @@ -857,6 +860,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, // listen for USER_SETUP_COMPLETE setting (per-user) resetUserSetupObserver(); + // disable profiling bars, since they overlap and clutter the output on app windows + ThreadedRenderer.overrideProperty("disableProfileBars", "true"); + + // Private API call to make the shadows look better for Recents + ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f)); + return mStatusBarView; } @@ -964,7 +973,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public void invokeAssistGesture(boolean vibrate) { mHandler.removeCallbacks(mInvokeAssist); - mAssistGestureManager.onGestureInvoked(vibrate); + mAssistManager.onGestureInvoked(vibrate); } public int getStatusBarHeight() { @@ -1044,7 +1053,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mNavigationBarView.getBackButton().setLongClickable(true); mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener); mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener); - mAssistGestureManager.onConfigurationChanged(); + mAssistManager.onConfigurationChanged(); } // For small-screen devices (read: phones) that lack hardware navigation buttons @@ -1805,6 +1814,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, startActivityDismissingKeyguard(intent, false, dismissShade); } + @Override + public void preventNextAnimation() { + overrideActivityPendingAppTransition(true /* keyguardShowing */); + } + public void setQsExpanded(boolean expanded) { mStatusBarWindowManager.setQsExpanded(expanded); } @@ -1924,6 +1938,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, return mHeadsUpManager.isSnoozed(sbn.getPackageName()); } + public boolean isKeyguardCurrentlySecure() { + return !mUnlockMethodCache.isCurrentlyInsecure(); + } + /** * All changes to the status bar and notifications funnel through here and are batched. */ @@ -2650,6 +2668,23 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, final boolean afterKeyguardGone = PreviewInflater.wouldLaunchResolverActivity( mContext, intent, mCurrentUserId); final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing(); + Runnable runnable = new Runnable() { + public void run() { + intent.setFlags( + Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + mContext.startActivityAsUser( + intent, new UserHandle(UserHandle.USER_CURRENT)); + overrideActivityPendingAppTransition( + keyguardShowing && !afterKeyguardGone); + } + }; + executeRunnableDismissingKeyguard(runnable, dismissShade, afterKeyguardGone); + } + + public void executeRunnableDismissingKeyguard(final Runnable runnable, + final boolean dismissShade, + final boolean afterKeyguardGone) { + final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing(); dismissKeyguardThenExecute(new OnDismissAction() { @Override public boolean onDismiss() { @@ -2660,12 +2695,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, ActivityManagerNative.getDefault() .keyguardWaitingForActivityDrawn(); } - intent.setFlags( - Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - mContext.startActivityAsUser( - intent, new UserHandle(UserHandle.USER_CURRENT)); - overrideActivityPendingAppTransition( - keyguardShowing && !afterKeyguardGone); + if (runnable != null) { + runnable.run(); + } } catch (RemoteException e) { } } @@ -3019,7 +3051,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mHandlerThread = null; } mContext.unregisterReceiver(mBroadcastReceiver); - mAssistGestureManager.destroy(); + mAssistManager.destroy(); } private boolean mDemoModeAllowed; @@ -3467,6 +3499,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mKeyguardIndicationController.showTransientIndication(R.string.camera_hint); } + public void onVoiceAssistHintStarted() { + mKeyguardIndicationController.showTransientIndication(R.string.voice_hint); + } + public void onPhoneHintStarted() { mKeyguardIndicationController.showTransientIndication(R.string.phone_hint); } @@ -3579,6 +3615,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, @Override public void setBouncerShowing(boolean bouncerShowing) { super.setBouncerShowing(bouncerShowing); + mStatusBarView.setBouncerShowing(bouncerShowing); disable(mDisabledUnmodified1, mDisabledUnmodified2, true /* animate */); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java index f2b2f66..a7fdadc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java @@ -162,7 +162,7 @@ public class MobileDataControllerImpl implements NetworkController.MobileDataCon usage.warningLevel = DEFAULT_WARNING_LEVEL; } if (usage != null) { - usage.carrier = mNetworkController.getMobileNetworkName(); + usage.carrier = mNetworkController.getMobileDataNetworkName(); } return usage; } catch (RemoteException e) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index c3c6b12..22bf47c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -84,6 +84,7 @@ public class MobileSignalController extends SignalController< mapIconSets(); mLastState.networkName = mCurrentState.networkName = mNetworkNameDefault; + mLastState.networkNameData = mCurrentState.networkNameData = mNetworkNameDefault; mLastState.enabled = mCurrentState.enabled = hasMobileData; mLastState.iconGroup = mCurrentState.iconGroup = mDefaultIcons; // Get initial data sim state. @@ -294,6 +295,7 @@ public class MobileSignalController extends SignalController< if (action.equals(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION)) { updateNetworkName(intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_SPN, false), intent.getStringExtra(TelephonyIntents.EXTRA_SPN), + intent.getStringExtra(TelephonyIntents.EXTRA_DATA_SPN), intent.getBooleanExtra(TelephonyIntents.EXTRA_SHOW_PLMN, false), intent.getStringExtra(TelephonyIntents.EXTRA_PLMN)); notifyListenersIfNecessary(); @@ -322,14 +324,18 @@ public class MobileSignalController extends SignalController< /** * Updates the network's name based on incoming spn and plmn. */ - void updateNetworkName(boolean showSpn, String spn, boolean showPlmn, String plmn) { + void updateNetworkName(boolean showSpn, String spn, String dataSpn, + boolean showPlmn, String plmn) { if (CHATTY) { - Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + " spn=" + spn + Log.d("CarrierLabel", "updateNetworkName showSpn=" + showSpn + + " spn=" + spn + " dataSpn=" + dataSpn + " showPlmn=" + showPlmn + " plmn=" + plmn); } StringBuilder str = new StringBuilder(); + StringBuilder strData = new StringBuilder(); if (showPlmn && plmn != null) { str.append(plmn); + strData.append(plmn); } if (showSpn && spn != null) { if (str.length() != 0) { @@ -342,6 +348,17 @@ public class MobileSignalController extends SignalController< } else { mCurrentState.networkName = mNetworkNameDefault; } + if (showSpn && dataSpn != null) { + if (strData.length() != 0) { + strData.append(mNetworkNameSeparator); + } + strData.append(dataSpn); + } + if (strData.length() != 0) { + mCurrentState.networkNameData = strData.toString(); + } else { + mCurrentState.networkNameData = mNetworkNameDefault; + } } /** @@ -492,6 +509,7 @@ public class MobileSignalController extends SignalController< static class MobileState extends SignalController.State { String networkName; + String networkNameData; boolean dataSim; boolean dataConnected; boolean isEmergency; @@ -505,6 +523,7 @@ public class MobileSignalController extends SignalController< MobileState state = (MobileState) s; dataSim = state.dataSim; networkName = state.networkName; + networkNameData = state.networkNameData; dataConnected = state.dataConnected; inetForNetwork = state.inetForNetwork; isEmergency = state.isEmergency; @@ -518,6 +537,7 @@ public class MobileSignalController extends SignalController< builder.append(','); builder.append("dataSim=").append(dataSim).append(','); builder.append("networkName=").append(networkName).append(','); + builder.append("networkNameData=").append(networkNameData).append(','); builder.append("dataConnected=").append(dataConnected).append(','); builder.append("inetForNetwork=").append(inetForNetwork).append(','); builder.append("isEmergency=").append(isEmergency).append(','); @@ -529,6 +549,7 @@ public class MobileSignalController extends SignalController< public boolean equals(Object o) { return super.equals(o) && Objects.equals(((MobileState) o).networkName, networkName) + && Objects.equals(((MobileState) o).networkNameData, networkNameData) && ((MobileState) o).dataSim == dataSim && ((MobileState) o).dataConnected == dataConnected && ((MobileState) o).isEmergency == isEmergency diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 6d88535..df133e4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -246,9 +246,9 @@ public class NetworkControllerImpl extends BroadcastReceiver return mDefaultSignalController; } - public String getMobileNetworkName() { + public String getMobileDataNetworkName() { MobileSignalController controller = getDataController(); - return controller != null ? controller.getState().networkName : ""; + return controller != null ? controller.getState().networkNameData : ""; } public boolean isEmergencyOnly() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java index 5d89e2f..4269c19 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/PreviewInflater.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -50,6 +51,15 @@ public class PreviewInflater { public View inflatePreview(Intent intent) { WidgetInfo info = getWidgetInfo(intent); + return inflatePreview(info); + } + + public View inflatePreviewFromService(ComponentName componentName) { + WidgetInfo info = getWidgetInfoFromService(componentName); + return inflatePreview(info); + } + + private KeyguardPreviewContainer inflatePreview(WidgetInfo info) { if (info == null) { return null; } @@ -77,8 +87,36 @@ public class PreviewInflater { return widgetView; } - private WidgetInfo getWidgetInfo(Intent intent) { + private WidgetInfo getWidgetInfoFromService(ComponentName componentName) { + PackageManager packageManager = mContext.getPackageManager(); + // Look for the preview specified in the service meta-data + try { + Bundle metaData = packageManager.getServiceInfo( + componentName, PackageManager.GET_META_DATA).metaData; + return getWidgetInfoFromMetaData(componentName.getPackageName(), metaData); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Failed to load preview; " + componentName.flattenToShortString() + + " not found", e); + } + return null; + } + + private WidgetInfo getWidgetInfoFromMetaData(String contextPackage, + Bundle metaData) { + if (metaData == null) { + return null; + } + int layoutId = metaData.getInt(META_DATA_KEYGUARD_LAYOUT); + if (layoutId == 0) { + return null; + } WidgetInfo info = new WidgetInfo(); + info.contextPackage = contextPackage; + info.layoutId = layoutId; + return info; + } + + private WidgetInfo getWidgetInfo(Intent intent) { PackageManager packageManager = mContext.getPackageManager(); final List<ResolveInfo> appList = packageManager.queryIntentActivitiesAsUser( intent, PackageManager.MATCH_DEFAULT_ONLY, KeyguardUpdateMonitor.getCurrentUser()); @@ -94,16 +132,8 @@ public class PreviewInflater { if (resolved == null || resolved.activityInfo == null) { return null; } - if (resolved.activityInfo.metaData == null || resolved.activityInfo.metaData.isEmpty()) { - return null; - } - int layoutId = resolved.activityInfo.metaData.getInt(META_DATA_KEYGUARD_LAYOUT); - if (layoutId == 0) { - return null; - } - info.contextPackage = resolved.activityInfo.packageName; - info.layoutId = layoutId; - return info; + return getWidgetInfoFromMetaData(resolved.activityInfo.packageName, + resolved.activityInfo.metaData); } public static boolean wouldLaunchResolverActivity(Context ctx, Intent intent, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java index 202063a..de28ac7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java @@ -582,7 +582,7 @@ public class StackScrollAlgorithm { return row.getIntrinsicHeight(); } else if (child instanceof ExpandableView) { ExpandableView expandableView = (ExpandableView) child; - return expandableView.getActualHeight(); + return expandableView.getIntrinsicHeight(); } return child == null? mCollapsedSize : child.getHeight(); } diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java index 23a65e8..ca32567 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java @@ -93,7 +93,7 @@ public class UsbResolverActivity extends ResolverActivity { } @Override - protected void onTargetSelected(TargetInfo target, boolean alwaysCheck) { + protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) { final ResolveInfo ri = target.getResolveInfo(); try { IBinder b = ServiceManager.getService(USB_SERVICE); @@ -129,5 +129,6 @@ public class UsbResolverActivity extends ResolverActivity { } catch (RemoteException e) { Log.e(TAG, "onIntentSelected failed", e); } + return true; } } diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java index 9434036..1e34663 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java @@ -16,6 +16,9 @@ package com.android.systemui.volume; +import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK; + +import android.accessibilityservice.AccessibilityServiceInfo; import android.animation.LayoutTransition; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; @@ -32,6 +35,7 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.media.AudioSystem; +import android.os.Debug; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -43,6 +47,8 @@ import android.util.SparseBooleanArray; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; +import android.view.View.AccessibilityDelegate; +import android.view.View.OnAttachStateChangeListener; import android.view.View.OnClickListener; import android.view.View.OnLayoutChangeListener; import android.view.View.OnTouchListener; @@ -50,6 +56,9 @@ import android.view.ViewGroup; import android.view.ViewGroup.MarginLayoutParams; import android.view.Window; import android.view.WindowManager; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; import android.view.animation.DecelerateInterpolator; import android.widget.ImageButton; import android.widget.LinearLayout; @@ -97,6 +106,7 @@ public class VolumeDialog { private final ZenFooter mZenFooter; private final LayoutTransition mLayoutTransition; private final Object mSafetyWarningLock = new Object(); + private final Accessibility mAccessibility = new Accessibility(); private boolean mShowing; private boolean mExpanded; @@ -174,6 +184,8 @@ public class VolumeDialog { mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer); mZenFooter.init(zenModeController); + mAccessibility.init(); + controller.addCallback(mControllerCallbackH, mHandler); controller.getState(); } @@ -409,10 +421,13 @@ public class VolumeDialog { protected void rescheduleTimeoutH() { mHandler.removeMessages(H.DISMISS); - final int timeout = computeTimeoutH(); - if (D.BUG) Log.d(TAG, "rescheduleTimeout " + timeout); - mHandler.sendMessageDelayed(mHandler - .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT, 0), timeout); + int timeout = -1; + if (!mAccessibility.mFeedbackEnabled) { + timeout = computeTimeoutH(); + mHandler.sendMessageDelayed(mHandler + .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT, 0), timeout); + } + if (D.BUG) Log.d(TAG, "rescheduleTimeout " + timeout + " " + Debug.getCaller()); mController.userActivity(); } @@ -475,6 +490,8 @@ public class VolumeDialog { if (res == mExpandButtonRes) return; mExpandButtonRes = res; mExpandButton.setImageResource(res); + mExpandButton.setContentDescription(mContext.getString(mExpanded ? + R.string.accessibility_volume_collapse : R.string.accessibility_volume_expand)); } private boolean isVisibleH(VolumeRow row, boolean isActive) { @@ -632,6 +649,7 @@ public class VolumeDialog { : (iconRes == R.drawable.ic_volume_media_bt || iconRes == row.iconRes) ? Events.ICON_STATE_UNMUTE : Events.ICON_STATE_UNKNOWN; + row.icon.setContentDescription(ss.name); // update slider updateVolumeRowSliderH(row, zenMuted); @@ -770,6 +788,7 @@ public class VolumeDialog { public void onConfigurationChanged() { updateWindowWidthH(); mSpTexts.update(); + mZenFooter.onConfigurationChanged(); } @Override @@ -931,6 +950,56 @@ public class VolumeDialog { } } + private final class Accessibility { + private AccessibilityManager mMgr; + private boolean mFeedbackEnabled; + + public void init() { + mMgr = (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); + mDialogView.addOnAttachStateChangeListener(new OnAttachStateChangeListener() { + @Override + public void onViewDetachedFromWindow(View v) { + // noop + } + + @Override + public void onViewAttachedToWindow(View v) { + updateFeedbackEnabled(); + } + }); + mDialogView.setAccessibilityDelegate(new AccessibilityDelegate() { + @Override + public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, + AccessibilityEvent event) { + rescheduleTimeoutH(); + return super.onRequestSendAccessibilityEvent(host, child, event); + } + }); + mMgr.addAccessibilityStateChangeListener(new AccessibilityStateChangeListener() { + @Override + public void onAccessibilityStateChanged(boolean enabled) { + updateFeedbackEnabled(); + } + }); + updateFeedbackEnabled(); + } + + private void updateFeedbackEnabled() { + mFeedbackEnabled = computeFeedbackEnabled(); + } + + private boolean computeFeedbackEnabled() { + final List<AccessibilityServiceInfo> services = + mMgr.getEnabledAccessibilityServiceList(FEEDBACK_ALL_MASK); + for (AccessibilityServiceInfo asi : services) { + if ((asi.feedbackType & FEEDBACK_ALL_MASK) != 0) { + return true; + } + } + return false; + } + } + private static class VolumeRow { private View view; private View space; diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java index 8aded45..ccb2b5a 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java @@ -36,10 +36,11 @@ public class ZenFooter extends LinearLayout { private static final String TAG = Util.logTag(ZenFooter.class); private final Context mContext; + private final SpTexts mSpTexts; private TextView mSummaryLine1; private TextView mSummaryLine2; - private View mEndNowButton; + private TextView mEndNowButton; private int mZen = -1; private ZenModeConfig mConfig; private ZenModeController mController; @@ -47,6 +48,7 @@ public class ZenFooter extends LinearLayout { public ZenFooter(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; + mSpTexts = new SpTexts(mContext); setLayoutTransition(new LayoutTransition()); } @@ -55,7 +57,10 @@ public class ZenFooter extends LinearLayout { super.onFinishInflate(); mSummaryLine1 = (TextView) findViewById(R.id.volume_zen_summary_line_1); mSummaryLine2 = (TextView) findViewById(R.id.volume_zen_summary_line_2); - mEndNowButton = findViewById(R.id.volume_zen_end_now); + mEndNowButton = (TextView) findViewById(R.id.volume_zen_end_now); + mSpTexts.add(mSummaryLine1); + mSpTexts.add(mSummaryLine2); + mSpTexts.add(mEndNowButton); } public void init(final ZenModeController controller) { @@ -122,4 +127,8 @@ public class ZenFooter extends LinearLayout { Util.setText(mSummaryLine2, line2); } + public void onConfigurationChanged() { + mSpTexts.update(); + } + } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index a176c98..29f461e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -306,6 +306,6 @@ public class NetworkControllerBaseTest extends SysuiTestCase { } protected void assertNetworkNameEquals(String expected) { - assertEquals("Network name", expected, mNetworkController.getMobileNetworkName()); + assertEquals("Network name", expected, mNetworkController.getMobileDataNetworkName()); } } diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml index 375c5d8..32e1e6d 100644 --- a/packages/VpnDialogs/AndroidManifest.xml +++ b/packages/VpnDialogs/AndroidManifest.xml @@ -24,7 +24,7 @@ <application android:label="VpnDialogs" android:allowBackup="false" > <activity android:name=".ConfirmDialog" - android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"> + android:theme="@*android:style/Theme.Material.DayNight.Dialog.Alert"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.DEFAULT"/> @@ -32,7 +32,7 @@ </activity> <activity android:name=".ManageDialog" - android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert" + android:theme="@*android:style/Theme.Material.DayNight.Dialog.Alert" android:noHistory="true"> <intent-filter> <action android:name="android.intent.action.MAIN"/> diff --git a/packages/WallpaperCropper/res/values/styles.xml b/packages/WallpaperCropper/res/values/styles.xml index a34b25a..e438c84 100644 --- a/packages/WallpaperCropper/res/values/styles.xml +++ b/packages/WallpaperCropper/res/values/styles.xml @@ -15,13 +15,13 @@ --> <resources> - <style name="Theme.WallpaperCropper" parent="@android:style/Theme.DeviceDefault"> + <style name="Theme.WallpaperCropper" parent="@android:style/Theme.Material.DayNight"> <item name="android:actionBarStyle">@style/WallpaperCropperActionBar</item> <item name="android:windowFullscreen">true</item> <item name="android:windowActionBarOverlay">true</item> </style> - <style name="WallpaperCropperActionBar" parent="android:style/Widget.DeviceDefault.ActionBar"> + <style name="WallpaperCropperActionBar" parent="@android:style/Widget.Material.ActionBar"> <item name="android:displayOptions">showCustom</item> <item name="android:background">#88000000</item> </style> |