Merge "Import translations. DO NOT MERGE"
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 87dec5d..3c9dd68 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -316,7 +316,7 @@
         StatsdStats::kMaxMetricsBytesPerConfig) {  // Too late. We need to start clearing data.
         // TODO(b/70571383): By 12/15/2017 add API to drop data directly
         ProtoOutputStream proto;
-        metricsManager.onDumpReport(time(nullptr) * NS_PER_SEC, &proto);
+        metricsManager.onDumpReport(timestampNs, &proto);
         StatsdStats::getInstance().noteDataDropped(key);
         VLOG("StatsD had to toss out metrics for %s", key.ToString().c_str());
     } else if (totalBytes > .9 * StatsdStats::kMaxMetricsBytesPerConfig) {
@@ -340,7 +340,7 @@
     for (auto& pair : mMetricsManagers) {
         const ConfigKey& key = pair.first;
         vector<uint8_t> data;
-        onDumpReportLocked(key, time(nullptr) * NS_PER_SEC, &data);
+        onDumpReportLocked(key, getElapsedRealtimeNs(), &data);
         // TODO: Add a guardrail to prevent accumulation of file on disk.
         string file_name = StringPrintf("%s/%ld_%d_%lld", STATS_DATA_DIR,
              (long)getWallClockSec(), key.GetUid(), (long long)key.GetId());
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 26db3af..c27b130 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -493,7 +493,7 @@
         }
         if (good) {
             vector<uint8_t> data;
-            mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), time(nullptr) * NS_PER_SEC,
+            mProcessor->onDumpReport(ConfigKey(uid, StrToInt64(name)), getElapsedRealtimeNs(),
                                      &data);
             // TODO: print the returned StatsLogReport to file instead of printing to logcat.
             if (proto) {
@@ -786,7 +786,7 @@
     VLOG("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid());
     if (checkCallingPermission(String16(kPermissionDump))) {
         ConfigKey configKey(ipc->getCallingUid(), key);
-        mProcessor->onDumpReport(configKey, time(nullptr) * NS_PER_SEC, output);
+        mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), output);
         return Status::ok();
     } else {
         return Status::fromExceptionCode(binder::Status::EX_SECURITY);
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 0a0d214..605dbd2 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -79,9 +79,8 @@
             ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
     public static final ParcelUuid SAP =
             ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB");
-    /* TODO: b/69623109 update this value. It will change to 16bit UUID!! */
     public static final ParcelUuid HearingAid =
-            ParcelUuid.fromString("7312C48F-22CC-497F-85FD-A0616A3B9E05");
+            ParcelUuid.fromString("0000FDF0-0000-1000-8000-00805f9b34fb");
 
     public static final ParcelUuid BASE_UUID =
             ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
diff --git a/core/java/android/security/keystore/recovery/BadCertificateFormatException.java b/core/java/android/security/keystore/recovery/BadCertificateFormatException.java
index e0781a5..4275c29 100644
--- a/core/java/android/security/keystore/recovery/BadCertificateFormatException.java
+++ b/core/java/android/security/keystore/recovery/BadCertificateFormatException.java
@@ -17,10 +17,8 @@
 package android.security.keystore.recovery;
 
 /**
- * Error thrown when the recovery agent supplies an invalid X509 certificate.
- *
+ * @deprecated Not used.
  * @hide
- * Deprecated
  */
 public class BadCertificateFormatException extends RecoveryControllerException {
     public BadCertificateFormatException(String msg) {
diff --git a/core/java/android/security/keystore/recovery/InternalRecoveryServiceException.java b/core/java/android/security/keystore/recovery/InternalRecoveryServiceException.java
index 218d26e..e62bfb1 100644
--- a/core/java/android/security/keystore/recovery/InternalRecoveryServiceException.java
+++ b/core/java/android/security/keystore/recovery/InternalRecoveryServiceException.java
@@ -19,6 +19,7 @@
 import android.annotation.SystemApi;
 
 import java.security.GeneralSecurityException;
+
 /**
  * An error thrown when something went wrong internally in the recovery service.
  *
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 0d262c9..0683e02 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -46,11 +46,11 @@
  * <p>The RecoveryController must be paired with a recovery agent. The recovery agent is responsible
  * for transporting the keychain to remote trusted hardware. This hardware must prevent brute force
  * attempts against the user's lock screen by limiting the number of allowed guesses (to, e.g., 10).
- * After  that number of incorrect guesses, the trusted hardware no longer allows access to the
+ * After that number of incorrect guesses, the trusted hardware no longer allows access to the
  * key chain.
  *
- * <p>For now only the recovery agent itself is able to create keys, so it is expected that the
- * recovery agent is itself the system app.
+ * <p>Only the recovery agent itself is able to create keys, so it is expected that the recovery
+ * agent is itself the system app.
  *
  * <p>A recovery agent requires the privileged permission
  * {@code android.Manifest.permission#RECOVER_KEYSTORE}.
diff --git a/core/java/android/security/keystore/recovery/RecoveryControllerException.java b/core/java/android/security/keystore/recovery/RecoveryControllerException.java
index 2733aca..1af61ce 100644
--- a/core/java/android/security/keystore/recovery/RecoveryControllerException.java
+++ b/core/java/android/security/keystore/recovery/RecoveryControllerException.java
@@ -19,10 +19,8 @@
 import java.security.GeneralSecurityException;
 
 /**
- * Base exception for errors thrown by {@link RecoveryController}.
- *
+ * @deprecated Not used.
  * @hide
- * Deprecated
  */
 public abstract class RecoveryControllerException extends GeneralSecurityException {
     RecoveryControllerException() { }
diff --git a/core/java/android/security/keystore/recovery/RecoverySession.java b/core/java/android/security/keystore/recovery/RecoverySession.java
index 069af91..e42c766 100644
--- a/core/java/android/security/keystore/recovery/RecoverySession.java
+++ b/core/java/android/security/keystore/recovery/RecoverySession.java
@@ -50,7 +50,7 @@
     }
 
     /**
-     * A new session, started by {@code recoveryManager}.
+     * A new session, started by the {@link RecoveryController}.
      */
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
     static RecoverySession newInstance(RecoveryController recoveryController) {
@@ -72,26 +72,6 @@
     }
 
     /**
-     * Starts a recovery session and returns a blob with proof of recovery secret possession.
-     * The method generates a symmetric key for a session, which trusted remote device can use to
-     * return recovery key.
-     *
-     * @param verifierPublicKey Encoded {@code java.security.cert.X509Certificate} with Public key
-     *     used to create the recovery blob on the source device.
-     *     Keystore will verify the certificate using root of trust.
-     * @param vaultParams Must match the parameters in the corresponding field in the recovery blob.
-     *     Used to limit number of guesses.
-     * @param vaultChallenge Data passed from server for this recovery session and used to prevent
-     *     replay attacks
-     * @param secrets Secrets provided by user, the method only uses type and secret fields.
-     * @return The recovery claim. Claim provides a b binary blob with recovery claim. It is
-     *     encrypted with verifierPublicKey and contains a proof of user secrets, session symmetric
-     *     key and parameters necessary to identify the counter with the number of failed recovery
-     *     attempts.
-     * @throws CertificateException if the {@code verifierPublicKey} is in an incorrect
-     *     format.
-     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
-     *     service.
      * @deprecated Use {@link #start(CertPath, byte[], byte[], List)} instead.
      * @removed
      */
@@ -132,7 +112,7 @@
      * @param vaultParams Must match the parameters in the corresponding field in the recovery blob.
      *     Used to limit number of guesses.
      * @param vaultChallenge Data passed from server for this recovery session and used to prevent
-     *     replay attacks
+     *     replay attacks.
      * @param secrets Secrets provided by user, the method only uses type and secret fields.
      * @return The recovery claim. Claim provides a b binary blob with recovery claim. It is
      *     encrypted with verifierPublicKey and contains a proof of user secrets, session symmetric
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 888db32..b163597 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -622,29 +622,25 @@
 
 // ---------------------------------------------------------------------------
 
-static int checkInternalFormat(SkColorType colorType, int format, int type)
+static int checkInternalFormat(SkColorType colorType, int internalformat,
+    int type)
 {
     switch(colorType) {
         case kN32_SkColorType:
+            return (type == GL_UNSIGNED_BYTE &&
+                internalformat == GL_RGBA) ? 0 : -1;
         case kAlpha_8_SkColorType:
-            if (type == GL_UNSIGNED_BYTE)
-                return 0;
+            return (type == GL_UNSIGNED_BYTE &&
+                internalformat == GL_ALPHA) ? 0 : -1;
         case kARGB_4444_SkColorType:
+            return (type == GL_UNSIGNED_SHORT_4_4_4_4 &&
+                internalformat == GL_RGBA) ? 0 : -1;
         case kRGB_565_SkColorType:
-            switch (type) {
-                case GL_UNSIGNED_SHORT_4_4_4_4:
-                case GL_UNSIGNED_SHORT_5_6_5:
-                case GL_UNSIGNED_SHORT_5_5_5_1:
-                    return 0;
-                case GL_UNSIGNED_BYTE:
-                    if (format == GL_LUMINANCE_ALPHA)
-                        return 0;
-            }
-            break;
+            return (type == GL_UNSIGNED_SHORT_5_6_5 &&
+                internalformat == GL_RGB) ? 0 : -1;
         case kRGBA_F16_SkColorType:
-            if (type == GL_HALF_FLOAT && format == GL_RGBA16F)
-                return 0;
-            break;
+            return (type == GL_HALF_FLOAT &&
+                internalformat == GL_RGBA16F) ? 0 : -1;
         default:
             break;
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/IconCache.java b/packages/SettingsLib/src/com/android/settingslib/utils/IconCache.java
new file mode 100644
index 0000000..3d55c4f
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/IconCache.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 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.utils;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.util.ArrayMap;
+
+
+/**
+ * Icon cache to avoid multiple loads on the same icon.
+ */
+public class IconCache {
+    private final Context mContext;
+    @VisibleForTesting
+    final ArrayMap<Icon, Drawable> mMap = new ArrayMap<>();
+
+    public IconCache(Context context) {
+        mContext = context;
+    }
+
+    public Drawable getIcon(Icon icon) {
+        if (icon == null) {
+            return null;
+        }
+        Drawable drawable = mMap.get(icon);
+        if (drawable == null) {
+            drawable = icon.loadDrawable(mContext);
+            updateIcon(icon, drawable);
+        }
+        return drawable;
+    }
+
+    public void updateIcon(Icon icon, Drawable drawable) {
+        mMap.put(icon, drawable);
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index df1a7a8..2482095 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -527,10 +527,7 @@
 
         WifiConfiguration connectionConfig = null;
         if (mLastInfo != null) {
-            // TODO(sghuman): Refactor to match config network id when updating configs below, and
-            // then update network info and wifi info only on match
-            connectionConfig = getWifiConfigurationForNetworkId(
-                    mLastInfo.getNetworkId(), configs);
+            connectionConfig = getWifiConfigurationForNetworkId(mLastInfo.getNetworkId(), configs);
         }
 
         // Rather than dropping and reacquiring the lock multiple times in this method, we lock
@@ -564,6 +561,17 @@
                 accessPoints.add(accessPoint);
             }
 
+            // If there were no scan results, create an AP for the currently connected network (if
+            // it exists).
+            // TODO(sghuman): Investigate if this works for an ephemeral (auto-connected) network
+            // when there are no scan results, as it may not have a valid WifiConfiguration
+            if (accessPoints.isEmpty() && connectionConfig != null) {
+                AccessPoint activeAp = new AccessPoint(mContext, connectionConfig);
+                activeAp.update(connectionConfig, mLastInfo, mLastNetworkInfo);
+                accessPoints.add(activeAp);
+                scoresToRequest.add(NetworkKey.createFromWifiInfo(mLastInfo));
+            }
+
             requestScoresForNetworkKeys(scoresToRequest);
             for (AccessPoint ap : accessPoints) {
                 ap.update(mScoreCache, mNetworkScoringUiEnabled, mMaxSpeedLabelScoreCacheAge);
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index 8fd4700..ca965f3 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -696,6 +696,36 @@
     }
 
     @Test
+    public void onStartShouldDisplayConnectedAccessPointWhenThereAreNoScanResults()
+            throws Exception {
+        Network mockNetwork = mock(Network.class);
+        when(mockWifiManager.getCurrentNetwork()).thenReturn(mockNetwork);
+
+        when(mockWifiManager.getConnectionInfo()).thenReturn(CONNECTED_AP_1_INFO);
+
+        NetworkInfo networkInfo = new NetworkInfo(
+                ConnectivityManager.TYPE_WIFI, 0, "Type Wifi", "subtype");
+        networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, "connected", "test");
+        when(mockConnectivityManager.getNetworkInfo(any(Network.class))).thenReturn(networkInfo);
+
+        // Don't return any scan results
+        when(mockWifiManager.getScanResults()).thenReturn(new ArrayList<>());
+
+        WifiTracker tracker = createMockedWifiTracker();
+        startTracking(tracker);
+
+        verify(mockWifiManager).getConnectionInfo();
+        verify(mockWifiManager, times(1)).getConfiguredNetworks();
+        verify(mockConnectivityManager).getNetworkInfo(any(Network.class));
+
+        // mStaleAccessPoints is true
+        verify(mockWifiListenerExecutor, never()).onAccessPointsChanged();
+
+        assertThat(tracker.getAccessPoints().size()).isEqualTo(1);
+        assertThat(tracker.getAccessPoints().get(0).isActive()).isTrue();
+    }
+
+    @Test
     public void stopTrackingShouldRemoveAllPendingWork() throws Exception {
         WifiTracker tracker = createMockedWifiTracker();
         startTracking(tracker);
@@ -778,7 +808,7 @@
 
         mAccessPointsChangedLatch = new CountDownLatch(1);
         tracker.mReceiver.onReceive(mContext, new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION));
-        assertThat(mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
+        assertThat(mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS)).isTrue();
 
         assertThat(tracker.getAccessPoints()).isEmpty();
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/IconCacheTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/IconCacheTest.java
new file mode 100644
index 0000000..026ad47
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/IconCacheTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 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.utils;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class IconCacheTest {
+    private Icon mIcon;
+    private Context mContext;
+    private IconCache mIconCache;
+
+    @Before
+    public void setUp() {
+        mContext = spy(RuntimeEnvironment.application);
+        mIcon = mock(Icon.class);
+        Drawable drawable = mock(Drawable.class);
+        doReturn(drawable).when(mIcon).loadDrawable(mContext);
+        mIconCache = new IconCache(mContext);
+    }
+
+    @Test
+    public void testGetIcon_iconisNull() {
+        assertThat(mIconCache.getIcon(null)).isNull();
+    }
+
+    @Test
+    public void testGetIcon_iconAlreadyLoaded() {
+        mIconCache.getIcon(mIcon);
+        verify(mIcon, times(1)).loadDrawable(mContext);
+        mIconCache.getIcon(mIcon);
+        verify(mIcon, times(1)).loadDrawable(mContext);
+    }
+
+    @Test
+    public void testGetIcon_iconLoadedFirstTime() {
+        mIconCache.getIcon(mIcon);
+        assertTrue(mIconCache.mMap.containsKey(mIcon));
+    }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index be1aa46..0d9a37a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2125,6 +2125,10 @@
 
             win.setLastReportedMergedConfiguration(mergedConfiguration);
 
+            // Update the last inset values here because the values are sent back to the client.
+            // The last inset values represent the last client state.
+            win.updateLastInsetValues();
+
             outFrame.set(win.mCompatFrame);
             outOverscanInsets.set(win.mOverscanInsets);
             outContentInsets.set(win.mContentInsets);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index a7fc470..ef0780a 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -1359,9 +1359,7 @@
                             UsbManager.USB_FUNCTION_NONE).equals(
                             getSystemProperty(USB_STATE_PROPERTY, UsbManager.USB_FUNCTION_NONE));
                 }
-                // Mask out adb, since it is stored in mAdbEnabled
-                mCurrentFunctions = UsbManager.usbFunctionsFromString(mCurrentFunctionsStr)
-                        & ~UsbManager.FUNCTION_ADB;
+                mCurrentFunctions = UsbManager.FUNCTION_NONE;
                 mCurrentUsbFunctionsReceived = true;
 
                 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index 0401737..db48984 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -57,7 +57,9 @@
     Button mCompleteButton;
     Button mAbortButton;
 
+    Bundle mAssistData;
     AssistStructure mAssistStructure;
+    AssistContent mAssistContent;
 
     static final int STATE_IDLE = 0;
     static final int STATE_LAUNCHING = 1;
@@ -169,19 +171,15 @@
     public void onHandleAssist(Bundle assistBundle) {
     }
 
-    @Override
-    public void onHandleAssist(Bundle data, AssistStructure structure, AssistContent content) {
-        mAssistStructure = structure;
-        if (mAssistVisualizer != null) {
-            if (mAssistStructure != null) {
-                mAssistVisualizer.setAssistStructure(mAssistStructure);
-            } else {
-                mAssistVisualizer.clearAssistData();
-            }
-        }
+    private void logAssistContentAndData(AssistContent content, Bundle data) {
         if (content != null) {
             Log.i(TAG, "Assist intent: " + content.getIntent());
+            Log.i(TAG, "Assist intent from app: " + content.isAppProvidedIntent());
             Log.i(TAG, "Assist clipdata: " + content.getClipData());
+            Log.i(TAG, "Assist structured data: " + content.getStructuredData());
+            Log.i(TAG, "Assist web uri: " + content.getWebUri());
+            Log.i(TAG, "Assist web uri from app: " + content.isAppProvidedWebUri());
+            Log.i(TAG, "Assist extras: " + content.getExtras());
         }
         if (data != null) {
             Uri referrer = data.getParcelable(Intent.EXTRA_REFERRER);
@@ -192,6 +190,21 @@
     }
 
     @Override
+    public void onHandleAssist(Bundle data, AssistStructure structure, AssistContent content) {
+        mAssistData = data;
+        mAssistStructure = structure;
+        mAssistContent = content;
+        if (mAssistVisualizer != null) {
+            if (mAssistStructure != null) {
+                mAssistVisualizer.setAssistStructure(mAssistStructure);
+            } else {
+                mAssistVisualizer.clearAssistData();
+            }
+        }
+        logAssistContentAndData(content, data);
+    }
+
+    @Override
     public void onHandleAssistSecondary(final Bundle data, final AssistStructure structure,
             final AssistContent content, int index, int count) {
         Log.i(TAG, "Got secondary activity assist data " + index + " of " + count);
@@ -246,6 +259,7 @@
     public void onClick(View v) {
         if (v == mTreeButton) {
             if (mAssistVisualizer != null) {
+                logAssistContentAndData(mAssistContent, mAssistData);
                 mAssistVisualizer.logTree();
             }
         } else if (v == mTextButton) {