diff options
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); + } } } |