Adding Quick Controls Viewer

Bug: 193149603
Bug: 194116816
Bug: 196424229
Test: manual
Change-Id: Ia0a1e4fb4cf6cb6c19a95567f47394bc76aabf11
Merged-In: Ia0a1e4fb4cf6cb6c19a95567f47394bc76aabf11
(cherry picked from commit 45a33f79de6a9a68c8563c235cfa4e97133b0789)
diff --git a/tests/EmbeddedKitchenSinkApp/Android.bp b/tests/EmbeddedKitchenSinkApp/Android.bp
index ef70cc9..3187120 100644
--- a/tests/EmbeddedKitchenSinkApp/Android.bp
+++ b/tests/EmbeddedKitchenSinkApp/Android.bp
@@ -46,6 +46,7 @@
         "androidx.appcompat_appcompat",
         "car-admin-ui-lib",
         "car-ui-lib",
+        "car-qc-lib",
         "android.hidl.base-V1.0-java",
         "android.hardware.automotive.vehicle-V2.0-java",
         "vehicle-hal-support-lib-for-test",
diff --git a/tests/EmbeddedKitchenSinkApp/res/layout/qc_viewer.xml b/tests/EmbeddedKitchenSinkApp/res/layout/qc_viewer.xml
new file mode 100644
index 0000000..d48284b
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/res/layout/qc_viewer.xml
@@ -0,0 +1,43 @@
+<!--
+  ~ Copyright (C) 2021 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.
+  -->
+ <LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center_horizontal">
+
+     <EditText
+         android:id="@+id/qc_uri_input"
+         android:layout_width="match_parent"
+         android:layout_height="wrap_content"
+         android:inputType="text"
+         android:singleLine="true"/>
+
+     <Button
+         android:id="@+id/submit_uri_btn"
+         android:layout_width="wrap_content"
+         android:layout_height="wrap_content"
+         android:text="Update QCView"/>
+
+     <com.android.car.qc.view.QCView
+         android:id="@+id/qc_view"
+         android:layout_width="match_parent"
+         android:layout_height="wrap_content"
+         android:gravity="center"
+         android:focusable="false"/>
+
+ </LinearLayout>
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
index beeac2a..d2591b9 100644
--- a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/KitchenSinkActivity.java
@@ -66,6 +66,7 @@
 import com.google.android.car.kitchensink.power.PowerTestFragment;
 import com.google.android.car.kitchensink.projection.ProjectionFragment;
 import com.google.android.car.kitchensink.property.PropertyTestFragment;
+import com.google.android.car.kitchensink.qc.QCViewerFragment;
 import com.google.android.car.kitchensink.rotary.RotaryFragment;
 import com.google.android.car.kitchensink.sensor.SensorsTestFragment;
 import com.google.android.car.kitchensink.storagelifetime.StorageLifetimeFragment;
@@ -199,6 +200,7 @@
             new FragmentMenuEntry("profile_user", ProfileUserFragment.class),
             new FragmentMenuEntry("projection", ProjectionFragment.class),
             new FragmentMenuEntry("property test", PropertyTestFragment.class),
+            new FragmentMenuEntry("qc viewer", QCViewerFragment.class),
             new FragmentMenuEntry("rotary", RotaryFragment.class),
             new FragmentMenuEntry("sensors", SensorsTestFragment.class),
             new FragmentMenuEntry("storage lifetime", StorageLifetimeFragment.class),
diff --git a/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/qc/QCViewerFragment.java b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/qc/QCViewerFragment.java
new file mode 100644
index 0000000..20e96aa
--- /dev/null
+++ b/tests/EmbeddedKitchenSinkApp/src/com/google/android/car/kitchensink/qc/QCViewerFragment.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2021 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.google.android.car.kitchensink.qc;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.EditText;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import com.android.car.qc.controller.RemoteQCController;
+import com.android.car.qc.view.QCView;
+
+import com.google.android.car.kitchensink.R;
+
+public final class QCViewerFragment extends Fragment {
+    private static final String KEY_CURRENT_URI_STRING = "CURRENT_URI_STRING";
+
+    private RemoteQCController mController;
+    private String mUriString;
+    private EditText mInput;
+    private Button mButton;
+    private QCView mQCView;
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        if (savedInstanceState != null) {
+            mUriString = savedInstanceState.getString(KEY_CURRENT_URI_STRING);
+        }
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
+        View v = inflater.inflate(R.layout.qc_viewer, container, false);
+        mInput = v.findViewById(R.id.qc_uri_input);
+        mButton = v.findViewById(R.id.submit_uri_btn);
+        mQCView = v.findViewById(R.id.qc_view);
+
+        mButton.setOnClickListener(v1 -> {
+            mUriString = mInput.getText().toString();
+            Uri uri = Uri.parse(mUriString);
+            updateQCView(uri);
+        });
+
+        if (mUriString != null) {
+            Uri uri = Uri.parse(mUriString);
+            updateQCView(uri);
+        }
+
+        return v;
+    }
+
+    @Override
+    public void onSaveInstanceState(@NonNull Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putString(KEY_CURRENT_URI_STRING, mUriString);
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        if (mController != null) {
+            mController.listen(true);
+        }
+    }
+
+    @Override
+    public void onStop() {
+        super.onStop();
+        if (mController != null) {
+            mController.listen(false);
+        }
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        mUriString = null;
+        if (mController != null) {
+            mController.destroy();
+            mController = null;
+        }
+    }
+
+    private void updateQCView(Uri uri) {
+        if (uri == null) {
+            return;
+        }
+        if (mController != null) {
+            // destroy old controller
+            mController.destroy();
+        }
+
+        mController = new RemoteQCController(getContext(), uri);
+        mController.addObserver(mQCView);
+        mController.listen(true);
+    }
+}