NIU Actions: Add privacy confirmation dialog

This adds a dialog to inform the user that the NIU Actions buttons need to send data to Google in order to function. The user can accept or reject this. The dialog will block use of the feature until the user accepts.

Bug: 191818216
Test: Manual (Pixel 3A with multiple user profiles)
Test: m -j RunLauncherGoGoogleRoboTests
Change-Id: Iedd056ce239de5269d02a31d28a9778efae34ede
This commit is contained in:
Jon Spivack 2021-06-24 14:55:40 -07:00
parent 419ee4599e
commit 58905b4f0a
9 changed files with 246 additions and 0 deletions

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/modal_dialog_corner_radius" />
</shape>

View File

@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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:id="@+id/niu_actions_confirmation_dialog_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_gravity="center">
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1"/>
<LinearLayout
android:layout_width="@dimen/modal_dialog_width"
android:layout_height="wrap_content"
android:background="@drawable/round_rect_dialog"
android:backgroundTint="?attr/modalDialogBackground"
android:orientation="vertical"
android:layout_gravity="center"
android:paddingTop="@dimen/modal_dialog_padding"
android:paddingLeft="@dimen/modal_dialog_padding"
android:paddingRight="@dimen/modal_dialog_padding"
android:paddingBottom="@dimen/modal_dialog_padding_bottom">
<TextView
style="@style/ModalDialogTitle"
android:id="@+id/niu_actions_confirmation_header"
android:text="@string/niu_actions_confirmation_title"/>
<Space
android:layout_width="0dp"
android:layout_height="@dimen/modal_dialog_vertical_spacer"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="@dimen/confirmation_dialog_text_height">
<TextView
style="@style/ModalDialogText"
android:id="@+id/niu_actions_confirmation_description"
android:text="@string/niu_actions_confirmation_text"/>
</ScrollView>
<Space
android:layout_width="0dp"
android:layout_height="@dimen/modal_dialog_vertical_spacer"/>
<LinearLayout
android:id="@+id/niu_actions_confirmation_buttons"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<Space
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"/>
<Button
style="@style/ModalDialogButton"
android:id="@+id/niu_actions_confirmation_reject"
android:text="@string/niu_actions_confirmation_no"/>
<Button
style="@style/ModalDialogButton"
android:id="@+id/niu_actions_confirmation_accept"
android:text="@string/niu_actions_confirmation_yes"/>
</LinearLayout>
</LinearLayout>
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" />
</LinearLayout>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<resources>
<!-- Modal Dialogs -->
<dimen name="modal_dialog_width">360dp</dimen>
<dimen name="confirmation_dialog_text_height">168dp</dimen>
</resources>

View File

@ -19,4 +19,6 @@
<attr name="overviewButtonTextColor" format="color" />
<attr name="overviewButtonIconColor" format="color" />
<attr name="overviewButtonBackgroundColor" format="color" />
<!-- Modal dialog theming -->
<attr name="modalDialogBackground" format="color" />
</resources>

View File

@ -20,4 +20,7 @@
<color name="go_overview_text_color_dark">#F8F9FA</color>
<color name="go_overview_button_color">#70FFFFFF</color>
<color name="go_overview_button_color_dark">#474747</color>
<!-- Modal Dialogs -->
<color name="go_modal_dialog_background">#FFFFFF</color>
<color name="go_modal_dialog_background_dark">#424242</color>
</resources>

View File

@ -28,4 +28,12 @@
<dimen name="overview_proactive_row_height">0dp</dimen>
<dimen name="overview_proactive_row_bottom_margin">24dp</dimen>
<dimen name="task_corner_radius_override">28dp</dimen>
<!-- Modal Dialogs -->
<dimen name="modal_dialog_width">288dp</dimen>
<dimen name="modal_dialog_padding">24dp</dimen>
<dimen name="modal_dialog_padding_bottom">8dp</dimen>
<dimen name="modal_dialog_vertical_spacer">12dp</dimen>
<dimen name="modal_dialog_corner_radius">8dp</dimen>
<dimen name="confirmation_dialog_text_height">216dp</dimen>
</resources>

View File

@ -11,4 +11,13 @@
<string name="action_translate">Translate</string>
<!-- Label for a button that triggers Search on a screenshot of the current app. [CHAR_LIMIT=40] -->
<string name="action_search">Lens</string>
<!-- ******* NIU Actions First-Run Confirmation Dialog ******* -->
<!-- Dialog title -->
<string name="niu_actions_confirmation_title">Translate or listen to text on screen</string>
<!-- Dialog content -->
<string name="niu_actions_confirmation_text">Information such as text on your screen, web addresses, and screenshots may be shared with Google.\n\nTo change what information you share, go to <b>Settings > Apps > Default apps > Digital assistant app</b>.</string>
<!-- Label for a button that rejects the feature. [CHAR_LIMIT=40] -->
<string name="niu_actions_confirmation_no">CANCEL</string>
<!-- Label for a button that accepts the feature. [CHAR_LIMIT=40] -->
<string name="niu_actions_confirmation_yes">GOT IT</string>
</resources>

View File

@ -20,12 +20,14 @@
<item name="overviewButtonTextColor">@color/go_overview_text_color</item>
<item name="overviewButtonIconColor">@color/go_overview_text_color</item>
<item name="overviewButtonBackgroundColor">@color/go_overview_button_color</item>
<item name="modalDialogBackground">@color/go_modal_dialog_background</item>
</style>
<style name="AppTheme.Dark" parent="@style/LauncherTheme.Dark">
<item name="overviewButtonTextColor">@color/go_overview_text_color_dark</item>
<item name="overviewButtonIconColor">@color/go_overview_text_color_dark</item>
<item name="overviewButtonBackgroundColor">@color/go_overview_button_color_dark</item>
<item name="modalDialogBackground">@color/go_modal_dialog_background_dark</item>
</style>
<!-- Overview -->
@ -56,4 +58,33 @@
<item name="android:layout_height">wrap_content</item>
<item name="android:orientation">vertical</item>
</style>
<!-- Modal Dialogs -->
<style name="ModalDialogTitle">
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:textSize">20sp</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:lineHeight">24dp</item>
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_gravity">center_horizontal</item>
</style>
<style name="ModalDialogText">
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:textSize">16sp</item>
<item name="android:textColor">?android:attr/textColorSecondary</item>
<item name="android:lineHeight">24dp</item>
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_gravity">center_horizontal</item>
</style>
<style name="ModalDialogButton" parent="@style/Widget.AppCompat.Button.Borderless">
<item name="android:textSize">14sp</item>
<item name="android:textColor">?android:attr/colorAccent</item>
<item name="android:lineHeight">20dp</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
</style>
</resources>

View File

@ -20,20 +20,31 @@ import static com.android.quickstep.views.OverviewActionsView.DISABLED_NO_THUMBN
import static com.android.quickstep.views.OverviewActionsView.DISABLED_ROTATED;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.assist.AssistContent;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.drawable.ColorDrawable;
import android.os.SystemClock;
import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.quickstep.util.AssistContentRequester;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.TaskThumbnailView;
@ -53,6 +64,7 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory {
public static final String ACTIONS_ERROR_CODE = "niu_actions_app_error_code";
public static final int ERROR_PERMISSIONS_STRUCTURE = 1;
public static final int ERROR_PERMISSIONS_SCREENSHOT = 2;
private static final String NIU_ACTIONS_CONFIRMED = "launcher_go.niu_actions_confirmed";
private static final String TAG = "TaskOverlayFactoryGo";
private AssistContentRequester mContentRequester;
@ -79,6 +91,9 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory {
private boolean mAssistStructurePermitted;
private boolean mAssistScreenshotPermitted;
private AssistContentRequester mFactoryContentRequester;
private SharedPreferences mSharedPreferences;
private String mPreviousAction;
private AlertDialog mConfirmationDialog;
private TaskOverlayGo(TaskThumbnailView taskThumbnailView,
AssistContentRequester assistContentRequester) {
@ -92,6 +107,12 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory {
@Override
public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix,
boolean rotated) {
if (mConfirmationDialog != null && mConfirmationDialog.isShowing()) {
// Redraw the dialog in case the layout changed
mConfirmationDialog.dismiss();
showConfirmationDialog();
}
getActionsView().updateDisabledFlags(DISABLED_NO_THUMBNAIL, thumbnail == null);
checkSettings();
if (thumbnail == null || TextUtils.isEmpty(mNIUPackageName)) {
@ -105,6 +126,7 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory {
boolean isAllowedByPolicy = mThumbnailView.isRealSnapshot() && !isManagedProfileTask;
getActionsView().setCallbacks(new OverlayUICallbacksGoImpl(isAllowedByPolicy, task));
mTaskPackageName = task.key.getPackageName();
mSharedPreferences = Utilities.getPrefs(mApplicationContext);
if (!mAssistStructurePermitted || !mAssistScreenshotPermitted) {
return;
@ -131,6 +153,12 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory {
* Creates and sends an Intent corresponding to the button that was clicked
*/
private void sendNIUIntent(String actionType) {
if (!mSharedPreferences.getBoolean(NIU_ACTIONS_CONFIRMED, false)) {
mPreviousAction = actionType;
showConfirmationDialog();
return;
}
Intent intent = createNIUIntent(actionType);
// Only add and send the image if the appropriate permissions are held
if (mAssistStructurePermitted && mAssistScreenshotPermitted) {
@ -218,6 +246,35 @@ public final class TaskOverlayFactoryGo extends TaskOverlayFactory {
public void setImageActionsAPI(ImageActionsApi imageActionsApi) {
mImageApi = imageActionsApi;
}
private void showConfirmationDialog() {
BaseDraggingActivity activity = BaseActivity.fromContext(getActionsView().getContext());
LayoutInflater inflater = LayoutInflater.from(activity);
View view = inflater.inflate(R.layout.niu_actions_confirmation_dialog, /* root */ null);
Button acceptButton = view.findViewById(R.id.niu_actions_confirmation_accept);
acceptButton.setOnClickListener(this::onNiuActionsConfirmationAccept);
Button rejectButton = view.findViewById(R.id.niu_actions_confirmation_reject);
rejectButton.setOnClickListener(this::onNiuActionsConfirmationReject);
mConfirmationDialog = new AlertDialog.Builder(activity)
.setView(view)
.create();
mConfirmationDialog.getWindow()
.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
mConfirmationDialog.show();
}
private void onNiuActionsConfirmationAccept(View v) {
mConfirmationDialog.dismiss();
mSharedPreferences.edit().putBoolean(NIU_ACTIONS_CONFIRMED, true).apply();
sendNIUIntent(mPreviousAction);
}
private void onNiuActionsConfirmationReject(View v) {
mConfirmationDialog.cancel();
}
}
/**