Merge "@Ignore for KeyguardControllerTest"
diff --git a/packages/Shell/res/drawable/ic_bug_report_black_24dp.xml b/packages/Shell/res/drawable/ic_bug_report_black_24dp.xml
new file mode 100644
index 0000000..a102cee
--- /dev/null
+++ b/packages/Shell/res/drawable/ic_bug_report_black_24dp.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M20,8h-2.81c-0.45,-0.78 -1.07,-1.45 -1.82,-1.96L17,4.41 15.59,3l-2.17,2.17C12.96,5.06 12.49,5 12,5c-0.49,0 -0.96,0.06 -1.41,0.17L8.41,3 7,4.41l1.62,1.63C7.88,6.55 7.26,7.22 6.81,8L4,8v2h2.09c-0.05,0.33 -0.09,0.66 -0.09,1v1L4,12v2h2v1c0,0.34 0.04,0.67 0.09,1L4,16v2h2.81c1.04,1.79 2.97,3 5.19,3s4.15,-1.21 5.19,-3L20,18v-2h-2.09c0.05,-0.33 0.09,-0.66 0.09,-1v-1h2v-2h-2v-1c0,-0.34 -0.04,-0.67 -0.09,-1L20,10L20,8zM14,16h-4v-2h4v2zM14,12h-4v-2h4v2z"
+        android:fillColor="#000000"/>
+</vector>
diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
index 2a5703a..1c49a55d 100644
--- a/packages/Shell/res/values/strings.xml
+++ b/packages/Shell/res/values/strings.xml
@@ -4,9 +4,9 @@
      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.
@@ -16,6 +16,9 @@
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label">Shell</string>
 
+    <!-- Title of notification channel for bug report related notifications. [CHAR LIMIT=50] -->
+    <string name="bugreport_notification_channel">Bug reports</string>
+
     <!-- Title of notification indicating a bugreport is being generated. [CHAR LIMIT=50] -->
     <string name="bugreport_in_progress_title">Bug report <xliff:g id="id">#%d</xliff:g> is being generated</string>
     <!-- Title of notification indicating a bugreport has been successfully captured. [CHAR LIMIT=50] -->
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 1df626f..bf5e6f8 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -57,6 +57,7 @@
 import android.app.AlertDialog;
 import android.app.Notification;
 import android.app.Notification.Action;
+import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
@@ -64,6 +65,7 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.net.Uri;
@@ -196,6 +198,8 @@
      */
     private static final String SCREENSHOT_DIR = "bugreports";
 
+    private static final String NOTIFICATION_CHANNEL_ID = "bugreports";
+
     /** Managed dumpstate processes (keyed by id) */
     private final SparseArray<DumpstateListener> mProcesses = new SparseArray<>();
 
@@ -240,6 +244,12 @@
         final Configuration conf = mContext.getResources().getConfiguration();
         mIsWatch = (conf.uiMode & Configuration.UI_MODE_TYPE_MASK) ==
                 Configuration.UI_MODE_TYPE_WATCH;
+        NotificationManager nm = NotificationManager.from(mContext);
+        nm.createNotificationChannel(
+                new NotificationChannel(NOTIFICATION_CHANNEL_ID,
+                        mContext.getString(R.string.bugreport_notification_channel),
+                        isTv(this) ? NotificationManager.IMPORTANCE_DEFAULT
+                                : NotificationManager.IMPORTANCE_LOW));
     }
 
     @Override
@@ -1008,13 +1018,16 @@
             sNotificationBundle.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
                     context.getString(com.android.internal.R.string.android_system_label));
         }
-        return new Notification.Builder(context)
+        return new Notification.Builder(context, NOTIFICATION_CHANNEL_ID)
                 .addExtras(sNotificationBundle)
                 .setCategory(Notification.CATEGORY_SYSTEM)
-                .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+                .setSmallIcon(
+                        isTv(context) ? R.drawable.ic_bug_report_black_24dp
+                                : com.android.internal.R.drawable.stat_sys_adb)
                 .setLocalOnly(true)
                 .setColor(context.getColor(
-                        com.android.internal.R.color.system_notification_accent_color));
+                        com.android.internal.R.color.system_notification_accent_color))
+                .extend(new Notification.TvExtender());
     }
 
     /**
@@ -1333,6 +1346,10 @@
         return false;
     }
 
+    private static boolean isTv(Context context) {
+        return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+    }
+
     /**
      * Checks whether a character is valid on bugreport names.
      */
diff --git a/services/core/java/com/android/server/policy/AccessibilityShortcutController.java b/services/core/java/com/android/server/policy/AccessibilityShortcutController.java
index eec1fef..cd55f50 100644
--- a/services/core/java/com/android/server/policy/AccessibilityShortcutController.java
+++ b/services/core/java/com/android/server/policy/AccessibilityShortcutController.java
@@ -29,6 +29,7 @@
 import android.media.RingtoneManager;
 import android.os.Handler;
 import android.os.UserHandle;
+import android.os.Vibrator;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -48,6 +49,11 @@
  */
 public class AccessibilityShortcutController {
     private static final String TAG = "AccessibilityShortcutController";
+    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
+            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+            .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY)
+            .build();
+
 
     private final Context mContext;
     private AlertDialog mAlertDialog;
@@ -100,6 +106,8 @@
         final int userId = ActivityManager.getCurrentUser();
         final int dialogAlreadyShown = Settings.Secure.getIntForUser(
                 cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId);
+
+        // Play a notification tone
         final Ringtone tone =
                 RingtoneManager.getRingtone(mContext, Settings.System.DEFAULT_NOTIFICATION_URI);
         if (tone != null) {
@@ -108,6 +116,18 @@
                 .build());
             tone.play();
         }
+
+        // Play a notification vibration
+        Vibrator vibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
+        if ((vibrator != null) && vibrator.hasVibrator()) {
+            // Don't check if haptics are disabled, as we need to alert the user that their
+            // way of interacting with the phone may change if they activate the shortcut
+            long[] vibePattern = PhoneWindowManager.getLongIntArray(mContext.getResources(),
+                    R.array.config_safeModeDisabledVibePattern);
+            vibrator.vibrate(vibePattern, -1, VIBRATION_ATTRIBUTES);
+        }
+
+
         if (dialogAlreadyShown == 0) {
             // The first time, we show a warning rather than toggle the service to give the user a
             // chance to turn off this feature before stuff gets enabled.
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index f7d3343..c9863c5 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -566,7 +566,10 @@
         pw.print(" rect=("); pw.print(mSurfaceX);
         pw.print(","); pw.print(mSurfaceY);
         pw.print(") "); pw.print(mSurfaceW);
-        pw.print(" x "); pw.println(mSurfaceH);
+        pw.print(" x "); pw.print(mSurfaceH);
+        pw.print(" transform=("); pw.print(mLastDsdx); pw.print(", ");
+        pw.print(mLastDtdx); pw.print(", "); pw.print(mLastDsdy);
+        pw.print(", "); pw.print(mLastDtdy); pw.println(")");
     }
 
     @Override
diff --git a/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java b/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java
index 8329d68..4d5f783 100644
--- a/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java
@@ -21,9 +21,11 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.os.Handler;
+import android.os.Vibrator;
 import android.provider.Settings;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -54,6 +56,7 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
+import static org.mockito.AdditionalMatchers.aryEq;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyObject;
@@ -67,6 +70,11 @@
 @RunWith(AndroidJUnit4.class)
 public class AccessibilityShortcutControllerTest {
     private static final String SERVICE_NAME_STRING = "fake.package/fake.service.name";
+    private static final long VIBRATOR_PATTERN_1 = 100L;
+    private static final long VIBRATOR_PATTERN_2 = 150L;
+    private static final int[] VIBRATOR_PATTERN_INT = {(int) VIBRATOR_PATTERN_1,
+            (int) VIBRATOR_PATTERN_2};
+    private static final long[] VIBRATOR_PATTERN_LONG = {VIBRATOR_PATTERN_1, VIBRATOR_PATTERN_2};
 
     private @Mock Context mContext;
     private @Mock FrameworkObjectProvider mFrameworkObjectProvider;
@@ -77,6 +85,8 @@
     private @Mock AccessibilityServiceInfo mServiceInfo;
     private @Mock Resources mResources;
     private @Mock Toast mToast;
+    private @Mock Vibrator mVibrator;
+    private @Mock ApplicationInfo mApplicationInfo;
 
     private MockContentResolver mContentResolver;
     private WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams();
@@ -85,10 +95,15 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
+        when(mVibrator.hasVibrator()).thenReturn(true);
+
+        when(mContext.getResources()).thenReturn(mResources);
+        when(mContext.getApplicationInfo()).thenReturn(mApplicationInfo);
+        when(mContext.getSystemService(Context.VIBRATOR_SERVICE)).thenReturn(mVibrator);
+
         mContentResolver = new MockContentResolver(mContext);
         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
         when(mContext.getContentResolver()).thenReturn(mContentResolver);
-        when(mContext.getResources()).thenReturn(mResources);
 
         when(mAccessibilityManagerService.getInstalledAccessibilityServiceList(anyInt()))
                 .thenReturn(Collections.singletonList(mServiceInfo));
@@ -104,6 +119,8 @@
                 .thenReturn(mToast);
 
         when(mResources.getString(anyInt())).thenReturn("Howdy %s");
+        when(mResources.getIntArray(anyInt())).thenReturn(VIBRATOR_PATTERN_INT);
+
         ResolveInfo resolveInfo = mock(ResolveInfo.class);
         when(resolveInfo.loadLabel(anyObject())).thenReturn("Service name");
         when(mServiceInfo.getResolveInfo()).thenReturn(resolveInfo);
@@ -171,6 +188,14 @@
     }
 
     @Test
+    public void testOnAccessibilityShortcut_vibrates() {
+        configureShortcutEnabled();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        accessibilityShortcutController.performAccessibilityShortcut();
+        verify(mVibrator).vibrate(aryEq(VIBRATOR_PATTERN_LONG), eq(-1), anyObject());
+    }
+
+    @Test
     public void testOnAccessibilityShortcut_firstTime_showsWarningDialog()
             throws Exception {
         configureShortcutEnabled();