1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.translation.cts; 18 19 import android.content.ComponentName; 20 import android.service.contentcapture.ActivityEvent; 21 import android.service.contentcapture.ContentCaptureService; 22 import android.service.contentcapture.DataShareCallback; 23 import android.util.ArraySet; 24 import android.util.Log; 25 import android.util.Pair; 26 import android.view.contentcapture.ContentCaptureContext; 27 import android.view.contentcapture.ContentCaptureEvent; 28 import android.view.contentcapture.ContentCaptureSessionId; 29 import android.view.contentcapture.DataRemovalRequest; 30 import android.view.contentcapture.DataShareRequest; 31 32 import androidx.annotation.NonNull; 33 import androidx.annotation.Nullable; 34 35 import java.util.Set; 36 import java.util.concurrent.CountDownLatch; 37 import java.util.concurrent.TimeUnit; 38 39 /** 40 * Implementation of {@link ContentCaptureService} used in CTS tests. 41 */ 42 public class CtsContentCaptureService extends ContentCaptureService { 43 44 private static final String TAG = "CtsContentCaptureService"; 45 46 public static final String SERVICE_PACKAGE = "android.translation.cts"; 47 public static final String SERVICE_NAME = SERVICE_PACKAGE + "/." 48 + CtsContentCaptureService.class.getSimpleName(); 49 50 public static final long GENERIC_TIMEOUT_MS = 10_000; 51 52 private static ServiceWatcher sServiceWatcher; 53 54 private ContentCaptureContext mContentCaptureContext; 55 private final CountDownLatch mSessionCreatedLatch = new CountDownLatch(1); 56 57 @Override onConnected()58 public void onConnected() { 59 Log.i(TAG, "onConnected."); 60 61 if (sServiceWatcher != null) { 62 sServiceWatcher.mService = this; 63 sServiceWatcher.mConnected.countDown(); 64 } 65 } 66 67 @Override onDisconnected()68 public void onDisconnected() { 69 Log.i(TAG, "onDisconnected."); 70 if (sServiceWatcher != null) { 71 sServiceWatcher.mService = null; 72 sServiceWatcher.mDisconnected.countDown(); 73 sServiceWatcher = null; 74 } 75 } 76 77 @Override onCreateContentCaptureSession(ContentCaptureContext context, ContentCaptureSessionId sessionId)78 public void onCreateContentCaptureSession(ContentCaptureContext context, 79 ContentCaptureSessionId sessionId) { 80 Log.i(TAG, "onCreateContentCaptureSession."); 81 mSessionCreatedLatch.countDown(); 82 mContentCaptureContext = context; 83 } 84 85 @Override onDestroyContentCaptureSession(ContentCaptureSessionId sessionId)86 public void onDestroyContentCaptureSession(ContentCaptureSessionId sessionId) { 87 Log.i(TAG, "onDestroyContentCaptureSession."); 88 } 89 90 @Override onContentCaptureEvent(ContentCaptureSessionId sessionId, ContentCaptureEvent event)91 public void onContentCaptureEvent(ContentCaptureSessionId sessionId, 92 ContentCaptureEvent event) { 93 94 } 95 96 @Override onDataRemovalRequest(DataRemovalRequest request)97 public void onDataRemovalRequest(DataRemovalRequest request) { 98 99 } 100 101 @Override onDataShareRequest(DataShareRequest request, DataShareCallback callback)102 public void onDataShareRequest(DataShareRequest request, DataShareCallback callback) { 103 104 } 105 106 @Override onActivityEvent(ActivityEvent event)107 public void onActivityEvent(ActivityEvent event) { 108 109 } 110 111 /** 112 * Set the ServiceWatcher that used to monitor the service status. 113 */ setServiceWatcher()114 public static ServiceWatcher setServiceWatcher() { 115 if (sServiceWatcher != null) { 116 throw new IllegalStateException("There Can Be Only One!"); 117 } 118 sServiceWatcher = new ServiceWatcher(); 119 return sServiceWatcher; 120 } 121 122 /** 123 * Resets the static state of this Service. Called before each test. 124 */ resetStaticState()125 public static void resetStaticState() { 126 sServiceWatcher = null; 127 } 128 129 /** 130 * Get the ContentCaptureContext that set by {@link #onCreateContentCaptureSession}. 131 */ getContentCaptureContext()132 ContentCaptureContext getContentCaptureContext() { 133 return mContentCaptureContext; 134 } 135 136 /** 137 * Wait the ContentCapture session created. 138 */ awaitSessionCreated(long timeoutMillis)139 void awaitSessionCreated(long timeoutMillis) { 140 try { 141 mSessionCreatedLatch.await(timeoutMillis, TimeUnit.MILLISECONDS); 142 } catch (InterruptedException e) { 143 // do nothing 144 } 145 } 146 147 /** 148 * Helper class to monitor the state of the service. 149 */ 150 public static final class ServiceWatcher { 151 private final CountDownLatch mConnected = new CountDownLatch(1); 152 private final CountDownLatch mDisconnected = new CountDownLatch(1); 153 154 CtsContentCaptureService mService; 155 private Pair<Set<String>, Set<ComponentName>> mAllowList; 156 157 @NonNull waitOnConnected()158 public CtsContentCaptureService waitOnConnected() throws InterruptedException { 159 await(mConnected, "not connected"); 160 161 if (mService == null) { 162 throw new IllegalStateException("not connected"); 163 } 164 if (mAllowList != null) { 165 Log.d(TAG, "Allow after created: " + mAllowList); 166 mService.setContentCaptureWhitelist(mAllowList.first, mAllowList.second); 167 } 168 return mService; 169 } 170 waitOnDisconnected()171 public void waitOnDisconnected() throws InterruptedException { 172 await(mDisconnected, "not disconnected"); 173 } 174 setAllowSelf()175 public void setAllowSelf() { 176 final ArraySet<String> pkgs = new ArraySet<>(1); 177 pkgs.add(SERVICE_PACKAGE); 178 mAllowList = new Pair<>(pkgs, null); 179 } 180 await(@onNull CountDownLatch latch, @NonNull String fmt, @Nullable Object... args)181 private static void await(@NonNull CountDownLatch latch, @NonNull String fmt, 182 @Nullable Object... args) 183 throws InterruptedException { 184 final boolean called = latch.await(GENERIC_TIMEOUT_MS, TimeUnit.MILLISECONDS); 185 if (!called) { 186 throw new IllegalStateException(String.format(fmt, args) 187 + " in " + GENERIC_TIMEOUT_MS + "ms"); 188 } 189 } 190 } 191 } 192