1 /*
2  * Copyright 2018 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 androidx.room.integration.testapp;
18 
19 import android.app.Service;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.os.IBinder;
23 import android.os.Process;
24 
25 import androidx.room.ExperimentalRoomApi;
26 import androidx.room.InvalidationTracker;
27 import androidx.room.Room;
28 import androidx.room.integration.testapp.database.Customer;
29 import androidx.room.integration.testapp.database.SampleDatabase;
30 
31 import org.jspecify.annotations.NonNull;
32 import org.jspecify.annotations.Nullable;
33 
34 import java.util.Set;
35 import java.util.concurrent.CountDownLatch;
36 import java.util.concurrent.TimeUnit;
37 
38 /**
39  * For testing use of {@link SampleDatabase} in a remote process.
40  */
41 public class SampleDatabaseService extends Service {
42 
43     private static final String DATABASE_NAME_PARAM = "db-name";
44 
45     private final ISampleDatabaseService.Stub mBinder = new ISampleDatabaseService.Stub() {
46 
47         @Override
48         public int getPid() {
49             return Process.myPid();
50         }
51 
52         @Override
53         public void insertCustomer(int id, String name, String lastName) {
54             final Customer customer = new Customer();
55             customer.setId(id);
56             customer.setName(name);
57             customer.setLastName(lastName);
58             mDatabase.getCustomerDao().insert(customer);
59         }
60 
61         @Override
62         public boolean waitForCustomer(int id, String name, String lastName) {
63             final CountDownLatch changed = new CountDownLatch(1);
64             final InvalidationTracker.Observer observer = new InvalidationTracker.Observer(
65                     Customer.class.getSimpleName()) {
66                 @Override
67                 public void onInvalidated(@NonNull Set<String> tables) {
68                     if (mDatabase.getCustomerDao().contains(id, name, lastName)) {
69                         changed.countDown();
70                     }
71                 }
72             };
73             mDatabase.getInvalidationTracker().addObserver(observer);
74             try {
75                 return changed.await(3, TimeUnit.SECONDS);
76             } catch (InterruptedException e) {
77                 return false;
78             } finally {
79                 mDatabase.getInvalidationTracker().removeObserver(observer);
80             }
81         }
82     };
83 
84     private SampleDatabase mDatabase;
85 
86     @Override
onCreate()87     public void onCreate() {
88         super.onCreate();
89     }
90 
91     /**
92      * Creates the test service for the given database name
93      * @param context The context to create the intent
94      * @param databaseName The database name to be used
95      * @return A new intent that can be used to connect to this service
96      */
intentFor(@onNull Context context, @NonNull String databaseName)97     public static @NonNull Intent intentFor(@NonNull Context context,
98             @NonNull String databaseName) {
99         Intent intent = new Intent(context, SampleDatabaseService.class);
100         intent.putExtra(DATABASE_NAME_PARAM, databaseName);
101         return intent;
102     }
103 
104     @Override
105     @ExperimentalRoomApi
onBind(Intent intent)106     public @Nullable IBinder onBind(Intent intent) {
107         String databaseName = intent.getStringExtra(DATABASE_NAME_PARAM);
108         if (databaseName == null) {
109             throw new IllegalArgumentException("Must pass database name in the intent");
110         }
111         if (mDatabase != null) {
112             throw new IllegalStateException("Cannot re-use the same service for different tests");
113         }
114         mDatabase = Room.databaseBuilder(this, SampleDatabase.class, databaseName)
115                 .enableMultiInstanceInvalidation()
116                 .build();
117         return mBinder;
118     }
119 
120     @Override
onUnbind(Intent intent)121     public boolean onUnbind(Intent intent) {
122         mDatabase.close();
123         return super.onUnbind(intent);
124     }
125 }
126