summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/Activity.java16
-rw-r--r--core/java/android/app/ActivityThread.java32
-rw-r--r--core/java/android/app/IApplicationThread.aidl4
-rw-r--r--core/java/android/view/translation/UiTranslationController.java50
-rw-r--r--core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java9
-rw-r--r--services/translation/java/com/android/server/translation/TranslationManagerService.java9
-rw-r--r--services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java22
7 files changed, 141 insertions, 1 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 55b858e3c602..415105f88f25 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -134,6 +134,8 @@ import android.view.autofill.IAutofillWindowPresenter;
import android.view.contentcapture.ContentCaptureContext;
import android.view.contentcapture.ContentCaptureManager;
import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
+import android.view.translation.TranslationSpec;
+import android.view.translation.UiTranslationController;
import android.widget.AdapterView;
import android.widget.Toast;
import android.widget.Toolbar;
@@ -957,6 +959,8 @@ public class Activity extends ContextThemeWrapper
private boolean mIsInMultiWindowMode;
private boolean mIsInPictureInPictureMode;
+ private UiTranslationController mUiTranslationController;
+
private final WindowControllerCallback mWindowControllerCallback =
new WindowControllerCallback() {
/**
@@ -8635,6 +8639,18 @@ public class Activity extends ContextThemeWrapper
ActivityClient.getInstance().unregisterRemoteAnimations(mToken);
}
+ /**
+ * Notify {@link UiTranslationController} the ui translation state is changed.
+ * @hide
+ */
+ public void updateUiTranslationState(int state, TranslationSpec sourceSpec,
+ TranslationSpec destSpec, List<AutofillId> viewIds) {
+ if (mUiTranslationController == null) {
+ mUiTranslationController = new UiTranslationController(this, getApplicationContext());
+ }
+ mUiTranslationController.updateUiTranslationState(state, sourceSpec, destSpec, viewIds);
+ }
+
class HostCallbacks extends FragmentHostCallback<Activity> {
public HostCallbacks() {
super(Activity.this /*activity*/);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e5c34c58e181..9b141b7bc649 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -175,6 +175,8 @@ import android.view.ViewRootImpl;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import android.view.autofill.AutofillId;
+import android.view.translation.TranslationSpec;
import android.webkit.WebView;
import com.android.internal.annotations.GuardedBy;
@@ -1808,6 +1810,18 @@ public final class ActivityThread extends ClientTransactionHandler {
data.appInfo = targetInfo;
sendMessage(H.INSTRUMENT_WITHOUT_RESTART, data);
}
+
+ @Override
+ public void updateUiTranslationState(IBinder activityToken, int state,
+ TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = activityToken;
+ args.arg2 = state;
+ args.arg3 = sourceSpec;
+ args.arg4 = destSpec;
+ args.arg5 = viewIds;
+ sendMessage(H.UPDATE_UI_TRANSLATION_STATE, args);
+ }
}
private @NonNull SafeCancellationTransport createSafeCancellationTransport(
@@ -1912,6 +1926,7 @@ public final class ActivityThread extends ClientTransactionHandler {
public static final int RELAUNCH_ACTIVITY = 160;
public static final int PURGE_RESOURCES = 161;
public static final int ATTACH_STARTUP_AGENTS = 162;
+ public static final int UPDATE_UI_TRANSLATION_STATE = 163;
public static final int INSTRUMENT_WITHOUT_RESTART = 170;
public static final int FINISH_INSTRUMENTATION_WITHOUT_RESTART = 171;
@@ -1958,6 +1973,7 @@ public final class ActivityThread extends ClientTransactionHandler {
case RELAUNCH_ACTIVITY: return "RELAUNCH_ACTIVITY";
case PURGE_RESOURCES: return "PURGE_RESOURCES";
case ATTACH_STARTUP_AGENTS: return "ATTACH_STARTUP_AGENTS";
+ case UPDATE_UI_TRANSLATION_STATE: return "UPDATE_UI_TRANSLATION_STATE";
case INSTRUMENT_WITHOUT_RESTART: return "INSTRUMENT_WITHOUT_RESTART";
case FINISH_INSTRUMENTATION_WITHOUT_RESTART:
return "FINISH_INSTRUMENTATION_WITHOUT_RESTART";
@@ -2142,6 +2158,12 @@ public final class ActivityThread extends ClientTransactionHandler {
case ATTACH_STARTUP_AGENTS:
handleAttachStartupAgents((String) msg.obj);
break;
+ case UPDATE_UI_TRANSLATION_STATE:
+ final SomeArgs args = (SomeArgs) msg.obj;
+ updateUiTranslationState((IBinder) args.arg1, (int) args.arg2,
+ (TranslationSpec) args.arg3, (TranslationSpec) args.arg4,
+ (List<AutofillId>) args.arg5);
+ break;
case INSTRUMENT_WITHOUT_RESTART:
handleInstrumentWithoutRestart((AppBindData) msg.obj);
break;
@@ -4020,6 +4042,16 @@ public final class ActivityThread extends ClientTransactionHandler {
}
}
+ private void updateUiTranslationState(IBinder activityToken, int state,
+ TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds) {
+ final ActivityClientRecord r = mActivities.get(activityToken);
+ if (r == null) {
+ Log.w(TAG, "updateUiTranslationState(): no activity for " + activityToken);
+ return;
+ }
+ r.activity.updateUiTranslationState(state, sourceSpec, destSpec, viewIds);
+ }
+
private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>();
/**
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index 890e957bdff4..b5294d5b6f4e 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -44,6 +44,8 @@ import android.os.ParcelFileDescriptor;
import android.os.PersistableBundle;
import android.os.RemoteCallback;
import android.os.SharedMemory;
+import android.view.autofill.AutofillId;
+import android.view.translation.TranslationSpec;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.content.ReferrerIntent;
@@ -157,4 +159,6 @@ oneway interface IApplicationThread {
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection,
in ApplicationInfo targetInfo);
+ void updateUiTranslationState(IBinder activityToken, int state, in TranslationSpec sourceSpec,
+ in TranslationSpec destSpec, in List<AutofillId> viewIds);
}
diff --git a/core/java/android/view/translation/UiTranslationController.java b/core/java/android/view/translation/UiTranslationController.java
new file mode 100644
index 000000000000..a810c2e6fb41
--- /dev/null
+++ b/core/java/android/view/translation/UiTranslationController.java
@@ -0,0 +1,50 @@
+/*
+ * 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 android.view.translation;
+
+import android.app.Activity;
+import android.content.Context;
+import android.view.autofill.AutofillId;
+
+import java.util.List;
+
+/**
+ * A controller to manage the ui translation requests.
+ *
+ * @hide
+ */
+public class UiTranslationController {
+
+ private static final String TAG = "UiTranslationController";
+
+ private final Activity mActivity;
+
+ private final Context mContext;
+
+ public UiTranslationController(Activity activity, Context context) {
+ mActivity = activity;
+ mContext = context;
+ }
+
+ /**
+ * Update the Ui translation state.
+ */
+ public void updateUiTranslationState(int state, TranslationSpec sourceSpec,
+ TranslationSpec destSpec, List<AutofillId> views) {
+ // Implement it. Deal with the each states
+ }
+}
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 5705dd530c16..f6d985b1788f 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -59,6 +59,8 @@ import android.platform.test.annotations.Presubmit;
import android.view.DisplayAdjustments.FixedRotationAdjustments;
import android.view.DisplayCutout;
import android.view.Surface;
+import android.view.autofill.AutofillId;
+import android.view.translation.TranslationSpec;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -70,6 +72,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
/**
@@ -686,5 +689,11 @@ public class TransactionParcelTests {
Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, ApplicationInfo targetInfo) {
}
+
+ @Override
+ public void updateUiTranslationState(IBinder activityToken, int state,
+ TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds) {
+
+ }
}
}
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerService.java b/services/translation/java/com/android/server/translation/TranslationManagerService.java
index 84c6e7be16be..6aadd23d211f 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerService.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerService.java
@@ -16,10 +16,12 @@
package com.android.server.translation;
+import static android.Manifest.permission.MANAGE_UI_TRANSLATION;
import static android.content.Context.TRANSLATION_MANAGER_SERVICE;
import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL;
import android.content.Context;
+import android.os.Binder;
import android.os.RemoteException;
import android.util.Slog;
import android.view.autofill.AutofillId;
@@ -58,6 +60,12 @@ public final class TranslationManagerService
return new TranslationManagerServiceImpl(this, mLock, resolvedUserId, disabled);
}
+ private void enforceCallerHasPermission(String permission) {
+ final String msg = "Permission Denial from pid =" + Binder.getCallingPid() + ", uid="
+ + Binder.getCallingUid() + " doesn't hold " + permission;
+ getContext().enforceCallingPermission(permission, msg);
+ }
+
final class TranslationManagerServiceStub extends ITranslationManager.Stub {
@Override
public void getSupportedLocales(IResultReceiver receiver, int userId)
@@ -91,6 +99,7 @@ public final class TranslationManagerService
public void updateUiTranslationState(@UiTranslationState int state,
TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
int taskId, int userId) {
+ enforceCallerHasPermission(MANAGE_UI_TRANSLATION);
synchronized (mLock) {
final TranslationManagerServiceImpl service = getServiceForUserLocked(userId);
if (service != null) {
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
index 5b1074fc4c0a..38be85c92197 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
@@ -33,7 +33,10 @@ import android.view.translation.UiTranslationManager.UiTranslationState;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.SyncResultReceiver;
+import com.android.server.LocalServices;
import com.android.server.infra.AbstractPerUserSystemService;
+import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerInternal.ActivityTokens;
import java.util.ArrayList;
import java.util.List;
@@ -51,11 +54,14 @@ final class TranslationManagerServiceImpl extends
@Nullable
private ServiceInfo mRemoteTranslationServiceInfo;
+ private ActivityTaskManagerInternal mActivityTaskManagerInternal;
+
protected TranslationManagerServiceImpl(
@NonNull TranslationManagerService master,
@NonNull Object lock, int userId, boolean disabled) {
super(master, lock, userId);
updateRemoteServiceLocked();
+ mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
}
@GuardedBy("mLock")
@@ -130,6 +136,20 @@ final class TranslationManagerServiceImpl extends
public void updateUiTranslationState(@UiTranslationState int state,
TranslationSpec sourceSpec, TranslationSpec destSpec, List<AutofillId> viewIds,
int taskId) {
- // TODO: implement this in next change
+ // TODO(b/177394471): use taskId as a temporary solution. The solution may use a token to
+ // content capture manager service find the activitytoken. Then we can use this
+ // activitytoken to find the activity to callback. But we need to change cc API so use
+ // temporary solution.
+ final ActivityTokens tokens = mActivityTaskManagerInternal.getTopActivityForTask(taskId);
+ if (tokens == null) {
+ Slog.w(TAG, "Unknown activity to query for update translation state.");
+ return;
+ }
+ try {
+ tokens.getApplicationThread().updateUiTranslationState(tokens.getActivityToken(), state,
+ sourceSpec, destSpec, viewIds);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Update UiTranslationState fail: " + e);
+ }
}
}