diff options
Diffstat (limited to 'packages')
26 files changed, 714 insertions, 240 deletions
diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml index 41bd168..cac6021 100644 --- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml @@ -65,9 +65,11 @@ <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલો કૉપિ કરી રહ્યાં છે.</item> </plurals> <string name="copy_preparing" msgid="3896202461003039386">"કૉપિ માટે તૈયારી કરી રહ્યું છે…"</string> - <!-- no translation found for copy_error_notification_title (5267616889076217261) --> + <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261"> + <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલો કૉપિ કરી શકાઈ નથી</item> + <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ફાઇલો કૉપિ કરી શકાઈ નથી</item> + </plurals> <string name="notification_touch_for_details" msgid="4483108577842961665">"વિગતો જોવા માટે ટચ કરો"</string> <string name="retry" msgid="7564024179122207376">"ફરી પ્રયાસ કરો"</string> - <!-- no translation found for copy_failure_alert_content (3715575000297709082) --> - <skip /> + <string name="copy_failure_alert_content" msgid="3715575000297709082">"આ ફાઇલો કૉપિ કરી નહોતી: <xliff:g id="LIST">%1$s</xliff:g>"</string> </resources> diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml index 978ea5a..56e4aa8 100644 --- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml +++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml @@ -65,9 +65,11 @@ <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ਫਾਈਲਾਂ ਕਾਪੀ ਕਰ ਰਿਹਾ ਹੈ।</item> </plurals> <string name="copy_preparing" msgid="3896202461003039386">"ਕਾਪੀ ਲਈ ਤਿਆਰ ਕਰ ਰਿਹਾ ਹੈ…"</string> - <!-- no translation found for copy_error_notification_title (5267616889076217261) --> + <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261"> + <item quantity="one"> <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਦੀ ਪ੍ਰਤੀਲਿਪੀ ਨਹੀਂ ਬਣਾ ਸਕਿਆ</item> + <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ਫ਼ਾਈਲਾਂ ਦੀ ਪ੍ਰਤੀਲਿਪੀ ਨਹੀਂ ਬਣਾ ਸਕਿਆ</item> + </plurals> <string name="notification_touch_for_details" msgid="4483108577842961665">"ਵੇਰਵੇ ਵੇਖਣ ਲਈ ਸਪਰਸ਼ ਕਰੋ"</string> <string name="retry" msgid="7564024179122207376">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string> - <!-- no translation found for copy_failure_alert_content (3715575000297709082) --> - <skip /> + <string name="copy_failure_alert_content" msgid="3715575000297709082">"ਇਹਨਾਂ ਫ਼ਾਈਲਾਂ ਦੀ ਪ੍ਰਤੀਲਿਪੀ ਨਹੀਂ ਬਣਾਈ ਗਈ: <xliff:g id="LIST">%1$s</xliff:g>"</string> </resources> diff --git a/packages/DocumentsUI/res/values-sq-rAL/strings.xml b/packages/DocumentsUI/res/values-sq-rAL/strings.xml index 0e10e5d..37c063f 100644 --- a/packages/DocumentsUI/res/values-sq-rAL/strings.xml +++ b/packages/DocumentsUI/res/values-sq-rAL/strings.xml @@ -65,9 +65,11 @@ <item quantity="one">Po kopjon <xliff:g id="COUNT_0">%1$d</xliff:g> skedar.</item> </plurals> <string name="copy_preparing" msgid="3896202461003039386">"Po përgatitet për kopjimin…"</string> - <!-- no translation found for copy_error_notification_title (5267616889076217261) --> + <plurals name="copy_error_notification_title" formatted="false" msgid="5267616889076217261"> + <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> skedarë nuk mund të kopjoheshin</item> + <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> skedar nuk mund të kopjohej</item> + </plurals> <string name="notification_touch_for_details" msgid="4483108577842961665">"Prek për të parë detajet"</string> <string name="retry" msgid="7564024179122207376">"Provo përsëri"</string> - <!-- no translation found for copy_failure_alert_content (3715575000297709082) --> - <skip /> + <string name="copy_failure_alert_content" msgid="3715575000297709082">"Këta skedarë nuk u kopjuan: <xliff:g id="LIST">%1$s</xliff:g>"</string> </resources> diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java index 2e0bece..9dd2b20 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,24 +462,35 @@ 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; + } finally { + if (copyError != null) { + try { + dstFile.closeWithError(copyError.getMessage()); + } catch (IOException e) { + Log.e(TAG, "Error closing destination", e); + } + } + // This also ensures the file descriptors are closed. + IoUtils.closeQuietly(src); + IoUtils.closeQuietly(dst); + } + + 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, e); + Log.w(TAG, "Source file gone: " + srcUri, copyError); // The source file is gone. } - } finally { - // This also ensures the file descriptors are closed. - IoUtils.closeQuietly(src); - IoUtils.closeQuietly(dst); } - if (errorOccurred || mIsCancelled) { + 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-sq-rAL/strings.xml b/packages/Keyguard/res/values-sq-rAL/strings.xml index d356588..f3943ea 100644 --- a/packages/Keyguard/res/values-sq-rAL/strings.xml +++ b/packages/Keyguard/res/values-sq-rAL/strings.xml @@ -108,6 +108,6 @@ <string name="kg_pin_accepted" msgid="1448241673570020097">"Kodi u pranua!"</string> <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nuk ka shërbim."</string> <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Butoni i metodës së ndërrimit të hyrjeve."</string> - <string name="airplane_mode" msgid="3122107900897202805">"Modaliteti i aeroplanit"</string> + <string name="airplane_mode" msgid="3122107900897202805">"Modaliteti \"në aeroplan\""</string> <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nuk njihet"</string> </resources> diff --git a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java index 25b1875..1cabcdf 100644 --- a/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java +++ b/packages/Keyguard/src/com/android/keyguard/EmergencyButton.java @@ -18,6 +18,7 @@ package com.android.keyguard; import android.content.Context; import android.content.Intent; +import android.content.res.Configuration; import android.os.PowerManager; import android.os.SystemClock; import android.os.UserHandle; @@ -104,6 +105,12 @@ public class EmergencyButton extends Button { updateEmergencyCallButton(); } + @Override + protected void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + updateEmergencyCallButton(); + } + /** * Shows the emergency dialer or returns the user to the existing call. */ diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java index ae4baad..4d89a8d 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -260,7 +260,6 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts); SecurityMode mode = mSecurityModel.getSecurityMode(); - final boolean usingPattern = mode == KeyguardSecurityModel.SecurityMode.Pattern; final int currentUser = KeyguardUpdateMonitor.getCurrentUser(); final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager(); final int failedAttemptsBeforeWipe = diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java index b8d9053..842cf73 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -58,13 +58,13 @@ 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; import android.telephony.TelephonyManager; import android.util.Log; import android.util.SparseBooleanArray; +import android.util.SparseIntArray; import com.google.android.collect.Lists; @@ -139,7 +139,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { private BatteryStatus mBatteryStatus; // Password attempts - private int mFailedAttempts = 0; + private SparseIntArray mFailedAttempts = new SparseIntArray(); private boolean mClockVisible; @@ -153,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 @@ -783,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(); @@ -800,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() { @@ -1260,28 +1262,20 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener { return mDeviceProvisioned; } - public int getFailedUnlockAttempts() { - return mFailedAttempts; - } - public void clearFailedUnlockAttempts() { - mFailedAttempts = 0; + mFailedAttempts.delete(sCurrentUser); } - public void clearFingerprintRecognized() { - mUserFingerprintAuthenticated.clear(); + public int getFailedUnlockAttempts() { + return mFailedAttempts.get(sCurrentUser, 0); } public void reportFailedUnlockAttempt() { - mFailedAttempts++; - } - - public boolean isClockVisible() { - return mClockVisible; + mFailedAttempts.put(sCurrentUser, getFailedUnlockAttempts() + 1); } - public int getPhoneState() { - return mPhoneState; + public void clearFingerprintRecognized() { + mUserFingerprintAuthenticated.clear(); } public boolean isSimPinVoiceSecure() { diff --git a/packages/PrintSpooler/res/values-sq-rAL/strings.xml b/packages/PrintSpooler/res/values-sq-rAL/strings.xml index 01eb719..0fbde0e 100644 --- a/packages/PrintSpooler/res/values-sq-rAL/strings.xml +++ b/packages/PrintSpooler/res/values-sq-rAL/strings.xml @@ -66,8 +66,8 @@ <string name="failed_notification_title_template" msgid="2256217208186530973">"Printeri ndeshi në gabim gjatë punës: <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <string name="blocked_notification_title_template" msgid="1175435827331588646">"Printeri bllokoi <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string> <plurals name="composite_notification_title_template" formatted="false" msgid="6940956968211733780"> - <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> punë printimi</item> - <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> punë printimi</item> + <item quantity="other"><xliff:g id="PRINT_JOB_NAME_1">%1$d</xliff:g> punë për printim</item> + <item quantity="one"><xliff:g id="PRINT_JOB_NAME_0">%1$d</xliff:g> punë për printim</item> </plurals> <string name="cancel" msgid="4373674107267141885">"Anulo"</string> <string name="restart" msgid="2472034227037808749">"Rifillo"</string> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index b2c9cd0..4082bf5 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -111,8 +111,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 +124,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 +141,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/SettingsProvider/res/values-sq-rAL/defaults.xml b/packages/SettingsProvider/res/values-sq-rAL/defaults.xml new file mode 100644 index 0000000..22443a5 --- /dev/null +++ b/packages/SettingsProvider/res/values-sq-rAL/defaults.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright (c) 2009, 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. + */ + --> + +<resources xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <string name="def_device_name" msgid="6309317409634339402">"%1$s %2$s"</string> + <string name="def_device_name_simple" msgid="9037785625140748221">"%1$s"</string> +</resources> diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml index fee2593..723a4d4 100644 --- a/packages/SystemUI/res/values-pa-rIN/strings.xml +++ b/packages/SystemUI/res/values-pa-rIN/strings.xml @@ -362,20 +362,13 @@ <string name="monitoring_title" msgid="169206259253048106">"ਨੈਟਵਰਕ ਨਿਰੀਖਣ ਕਰ ਰਿਹਾ ਹੈ"</string> <string name="disable_vpn" msgid="4435534311510272506">"VPN ਨੂੰ ਅਸਮਰੱਥ ਬਣਾਓ"</string> <string name="disconnect_vpn" msgid="1324915059568548655">"VPN ਨੂੰ ਡਿਸਕਨੈਕਟ ਕਰੋ"</string> - <!-- no translation found for monitoring_description_device_owned (5780988291898461883) --> - <skip /> - <!-- no translation found for monitoring_description_profile_owned (8110044290898637925) --> - <skip /> - <!-- no translation found for monitoring_description_device_and_profile_owned (1664428184778531249) --> - <skip /> - <!-- no translation found for monitoring_description_vpn (912328761766161919) --> - <skip /> - <!-- no translation found for monitoring_description_vpn_device_owned (3090670777499161246) --> - <skip /> - <!-- no translation found for monitoring_description_vpn_profile_owned (2224494839524715272) --> - <skip /> - <!-- no translation found for monitoring_description_vpn_device_and_profile_owned (2198546817407897093) --> - <skip /> + <string name="monitoring_description_device_owned" msgid="5780988291898461883">"ਤੁਹਾਡੀ ਡਿਵਾਈਸ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਵੱਲੋਂ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।\n\nਤੁਹਾਡਾ ਪ੍ਰਬੰਧਕ ਸੈਟਿੰਗਾਂ, ਕਾਰਪੋਰੇਟ ਪਹੁੰਚ, ਐਪਸ, ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਨਾਲ ਸੰਬੰਧਿਤ ਡਾਟਾ ਅਤੇ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਦੀ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਜਾਣਕਾਰੀ ਦਾ ਨਿਰੀਖਣ ਅਤੇ ਉਸਨੂੰ ਵਿਵਸਥਿਤ ਕਰ ਸਕਦਾ ਹੈ। ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string> + <string name="monitoring_description_profile_owned" msgid="8110044290898637925">"ਤੁਹਾਡੀ ਕੰਮ ਪ੍ਰੋਫਾਈਲ <xliff:g id="ORGANIZATION">%1$s</xliff:g>ਵੱਲੋਂ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।\n\nਤੁਹਾਡਾ ਪ੍ਰਬੰਧਕ ਤੁਹਾਡੀ ਨੈਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰਨ ਵਿੱਚ ਸਮਰੱਥ ਹੈ, ਈਮੇਲਾਂ, ਐਪਸ ਅਤੇ ਸੁਰੱਖਿਅਤ ਵੈਬਸਾਈਟਾਂ ਸਮੇਤ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣਾ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string> + <string name="monitoring_description_device_and_profile_owned" msgid="1664428184778531249">"ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਇਸ ਵੱਲੋਂ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>.\nਤੁਹਾਡੀ ਕੰਮਪ੍ਰੋਫਾਈਲ ਇਸ ਵੱਲੋਂ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>.\n\nਤੁਹਾਡਾ ਪ੍ਰਬੰਧਕ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਅਤੇ ਨੈਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦਾ ਹੈ ਜਿਸ ਵਿੱਚ ਸ਼ਾਮਲ ਹਨ ਈਮੇਲਾਂ, ਐਪਸ ਅਤੇ ਸੁਰੱਖਿਅਤ ਵੈਬਸਾਈਟਾਂ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string> + <string name="monitoring_description_vpn" msgid="912328761766161919">"ਤੁਸੀਂ ਇੱਕ ਐਪ ਨੂੰ ਇੱਕ VPN ਕਨੈਕਸ਼ਨ ਸੈਟ ਅਪ ਕਰਨ ਦੀ ਅਨੁਮਤੀ ਦਿੱਤੀ ਹੈ।\n\nਇਹ ਐਪ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਅਤੇ ਨੈਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦਾ ਹੈ, ਈਮੇਲਾਂ, ਐਪਸ ਅਤੇ ਸੁਰੱਖਿਅਤ ਵੈਬਸਾਈਟਾਂ ਸਮੇਤ।"</string> + <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"ਤੁਹਾਡੀ ਡਿਵਾਈਸ <xliff:g id="ORGANIZATION">%1$s</xliff:g>ਵੱਲੋਂ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।\n\nਪ੍ਰਬੰਧਕ ਸੈਟਿੰਗਾਂ, ਕਾਰਪੋਰੇਟ ਪਹੁੰਚ, ਐਪਸ, ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਨਾਲ ਸੰਬੰਧਿਤ ਡਾਟਾ ਅਤੇ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਦੀ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਜਾਣਕਾਰੀ ਦਾ ਨਿਰੀਖਣ ਅਤੇ ਉਸਨੂੰ ਵਿਵਸਥਿਤ ਕਰ ਸਕਦਾ ਹੈ।\n\nਤੁਸੀਂ ਇੱਕ VPN ਨਾਲ ਵੀ ਕਨੈਕਟ ਕੀਤਾ ਹੈ, ਜੋ ਤੁਹਾਡੀ ਨਿੱਜੀ ਨੈਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦਾ ਹੈ, ਈਮੇਲਾਂ, ਐਪਸ ਅਤੇ ਵੈਬਸਾਈਟਾਂ ਸਮੇਤ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string> + <string name="monitoring_description_vpn_profile_owned" msgid="2224494839524715272">"ਤੁਹਾਡੀ ਕੰਮ ਪ੍ਰੋਫਾਈਲ <xliff:g id="ORGANIZATION">%1$s</xliff:g>ਵੱਲੋਂ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।\n\nਤੁਹਾਡਾ ਪ੍ਰਬੰਧਕ ਤੁਹਾਡੀ ਨੈਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰਨ ਵਿੱਚ ਸਮਰੱਥ ਹੈ, ਈਮੇਲਾਂ, ਐਪਸ ਅਤੇ ਸੁਰੱਖਿਅਤ ਵੈਬਸਾਈਟਾਂ ਸਮੇਤ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣਾ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।\n\nਤੁਸੀਂ ਇੱਕ VPN ਨਾਲ ਵੀ ਕਨੈਕਟ ਕੀਤਾ ਹੈ, ਜੋ ਤੁਹਾਡੀ ਨੈਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦਾ ਹੈ।"</string> + <string name="monitoring_description_vpn_device_and_profile_owned" msgid="2198546817407897093">"ਤੁਹਾਡੀ ਡਿਵਾਈਸ <xliff:g id="ORGANIZATION_0">%1$s</xliff:g>ਵੱਲੋਂ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ।\nਤੁਹਾਡੀ ਕੰਮ ਪ੍ਰੋਫਾਈਲ ਇਸ ਵੱਲੋਂ ਵਿਵਸਥਿਤ ਕੀਤੀ ਜਾਂਦੀ ਹੈ:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>.\n\nਤੁਹਾਡਾ ਪ੍ਰਬੰਧਕ ਤੁਹਾਡੀ ਨੈਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰਨ ਵਿੱਚ ਸਮਰੱਥ ਹੈ ਜਿਸ ਵਿੱਚ ਸ਼ਾਮਲ ਹਨ ਈਮੇਲਾਂ, ਐਪਸ ਅਤੇ ਸੁਰੱਖਿਅਤ ਵੈਬਸਾਈਟਾਂ। \n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਬੰਧਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।\n\nਤੁਸੀਂ ਇੱਕ VPN ਨਾਲ ਵੀ ਕਨੈਕਟ ਕੀਤਾ ਹੈ, ਜੋ ਤੁਹਾਡੀ ਨਿੱਜੀ ਨੈਟਵਰਕ ਗਤੀਵਿਧੀ ਦਾ ਨਿਰੀਖਣ ਕਰ ਸਕਦਾ ਹੈ"</string> <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"ਡਿਵਾਈਸ ਲੌਕ ਰਹੇਗੀ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਮੈਨੂਅਲੀ ਅਨਲੌਕ ਨਹੀਂ ਕਰਦੇ"</string> <string name="hidden_notifications_title" msgid="7139628534207443290">"ਤੇਜ਼ੀ ਨਾਲ ਸੂਚਨਾਵਾਂ ਪ੍ਰਾਪਤ ਕਰੋ"</string> <string name="hidden_notifications_text" msgid="2326409389088668981">"ਅਨਲੌਕ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਉਹਨਾਂ ਨੂੰ ਦੇਖੋ"</string> diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml index e70254c..38fdcfd 100644 --- a/packages/SystemUI/res/values-sq-rAL/strings.xml +++ b/packages/SystemUI/res/values-sq-rAL/strings.xml @@ -179,12 +179,12 @@ <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Modaliteti \"në aeroplan\" është i aktivizuar."</string> <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Modaliteti \"në aeroplan\" është i çaktivizuar."</string> <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Modaliteti \"në aeroplan\" është i aktivizuar."</string> - <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Mos shqetëso\" i aktivizuar, vetëm me prioritet."</string> - <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\"Mos shqetëso\" i aktivizuar, asnjë ndërprerje."</string> - <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"Mos shqetëso\" i aktivizuar, vetëm alarmet."</string> - <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Mos shqetëso\" i çaktivizuar."</string> - <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Mos shqetëso\" i çaktivizuar."</string> - <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Mos shqetëso\" i aktivizuar."</string> + <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Mos shqetëso\" është i aktivizuar, vetëm me prioritet."</string> + <string name="accessibility_quick_settings_dnd_none_on" msgid="5910777408232088752">"\"Mos shqetëso\" është i aktivizuar, asnjë ndërprerje."</string> + <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"Mos shqetëso\" është i aktivizuar, vetëm alarmet."</string> + <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Mos shqetëso\" është i çaktivizuar."</string> + <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Mos shqetëso\" është i çaktivizuar."</string> + <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Mos shqetëso\" është i aktivizuar."</string> <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"\"Bluetooth-i\" është i çaktivizuar."</string> <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"\"Bluetooth-i\" është i aktivizuar."</string> <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"\"Bluetooth-i\" po lidhet."</string> @@ -362,20 +362,13 @@ <string name="monitoring_title" msgid="169206259253048106">"Monitorimi i rrjetit"</string> <string name="disable_vpn" msgid="4435534311510272506">"Çaktivizo VPN-në"</string> <string name="disconnect_vpn" msgid="1324915059568548655">"Shkëput VPN-në"</string> - <!-- no translation found for monitoring_description_device_owned (5780988291898461883) --> - <skip /> - <!-- no translation found for monitoring_description_profile_owned (8110044290898637925) --> - <skip /> - <!-- no translation found for monitoring_description_device_and_profile_owned (1664428184778531249) --> - <skip /> - <!-- no translation found for monitoring_description_vpn (912328761766161919) --> - <skip /> - <!-- no translation found for monitoring_description_vpn_device_owned (3090670777499161246) --> - <skip /> - <!-- no translation found for monitoring_description_vpn_profile_owned (2224494839524715272) --> - <skip /> - <!-- no translation found for monitoring_description_vpn_device_and_profile_owned (2198546817407897093) --> - <skip /> + <string name="monitoring_description_device_owned" msgid="5780988291898461883">"Pajisja jote menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratori yt mund të monitorojë dhe të menaxhojë cilësimet, qasjen e korporatës, aplikacionet, të dhënat e lidhura me pajisjen tënde, si dhe informacionet e vendndodhjes së pajisjes tënde. Për më shumë informacione, kontakto me administratorin tënd."</string> + <string name="monitoring_description_profile_owned" msgid="8110044290898637925">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratori yt mund të monitorojë aktivitetin e rrjetit, duke përfshirë emailet, aplikacionet dhe sajtet e sigurta të uebit.\n\nPër më shumë informacione, kontakto me administratorin tënd."</string> + <string name="monitoring_description_device_and_profile_owned" msgid="1664428184778531249">"Pajisja jote menaxhohet nga:\n<xliff:g id="ORGANIZATION_0">%1$s</xliff:g>.\nProfili yt i punës menaxhohet nga:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>.\n\nAdministratori yt mund të monitorojë pajisjen tënde dhe aktivitetin e rrjetit, duke përfshirë emailet, aplikacionet dhe sajtet e sigurta të uebit.\n\nPër më shumë informacione, kontakto me administratorin."</string> + <string name="monitoring_description_vpn" msgid="912328761766161919">"I dhe leje një aplikacioni që të konfigurojë një lidhje VPN.\n\nKy aplikacion mund të monitorojë pajisjen tënde dhe aktivitetin e rrjetit, duke përfshirë emailet, aplikacionet dhe sajtet e sigurta të uebit."</string> + <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"Pajisja jote menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratori yt mund të monitorojë dhe të menaxhojë cilësimet, qasjen e korporatës, aplikacionet, të dhënat e lidhura me pajisjen dhe informacionet e vendndodhjes së pajisjes.\n\nJe i lidhur me një rrjet VPN që mund të monitorojë aktivitetin tënd të rrjetit, duke përfshirë emailet, aplikacionet dhe sajtet e uebit.\n\nPër më shumë informacione, kontakto me administratorin."</string> + <string name="monitoring_description_vpn_profile_owned" msgid="2224494839524715272">"Profili yt i punës menaxhohet nga <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdministratori yt mund të monitorojë aktivitetin tënd të rrjetit, duke përfshirë emailet, aplikacionet dhe sajtet e sigurta të uebit.\n\nPër më shumë informacione, kontakto me administratorin tënd.\n\nJe i lidhur po ashtu me një rrjet VPN që mund të monitorojë aktivitetin tënd të rrjetit."</string> + <string name="monitoring_description_vpn_device_and_profile_owned" msgid="2198546817407897093">"Pajisja jote menaxhohet nga <xliff:g id="ORGANIZATION_0">%1$s</xliff:g>.\nProfili yt i punës menaxhohet nga:\n<xliff:g id="ORGANIZATION_1">%2$s</xliff:g>.\n\nAdministratori yt mund të monitorojë aktivitetin tënd të rrjetit, duke përfshirë emailet, aplikacionet dhe sajtet e sigurta të uebit.\n\nPër më shumë informacione, kontakto me administratorin tënd.\n\nJe i lidhur po ashtu me një rrjet VPN që mund të monitorojë aktivitetin e rrjetit tënd personal"</string> <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Pajisje do të qëndrojë e kyçur derisa ta shkyçësh manualisht"</string> <string name="hidden_notifications_title" msgid="7139628534207443290">"Merr njoftime më shpejt"</string> <string name="hidden_notifications_text" msgid="2326409389088668981">"Shikoji para se t\'i shkyçësh"</string> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 80fecac..b836af6 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -951,6 +951,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/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/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index f5ef1d2..4e46854 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -3586,6 +3586,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/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java index 9434036..7115897 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); @@ -931,6 +949,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/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()); } } |