Skip to content

Commit 5012986

Browse files
committed
implement few unimplemented methods
1 parent 1eacce1 commit 5012986

File tree

5 files changed

+294
-7
lines changed

5 files changed

+294
-7
lines changed

play-services-wearable/core/src/main/java/org/microg/gms/wearable/ClockworkNodePreferences.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,15 @@ public long getNextSeqId() {
7676
return seqIdBlock + seqIdInBlock++;
7777
}
7878
}
79+
80+
public void clear() {
81+
synchronized (lock) {
82+
SharedPreferences preferences = context.getSharedPreferences(
83+
CLOCKWORK_NODE_PREFERENCES, Context.MODE_PRIVATE);
84+
preferences.edit().clear().commit();
85+
86+
seqIdBlock = 0;
87+
seqIdInBlock = -1;
88+
}
89+
}
7990
}

play-services-wearable/core/src/main/java/org/microg/gms/wearable/WearableServiceImpl.java

Lines changed: 234 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,16 @@
1818

1919
import android.Manifest;
2020
import android.content.Context;
21+
import android.content.pm.ApplicationInfo;
22+
import android.content.pm.PackageManager;
23+
import android.database.Cursor;
24+
import android.database.sqlite.SQLiteDatabase;
2125
import android.net.Uri;
2226
import android.os.Handler;
2327
import android.os.Parcel;
2428
import android.os.ParcelFileDescriptor;
2529
import android.os.RemoteException;
30+
import android.text.TextUtils;
2631
import android.util.Base64;
2732
import android.util.Log;
2833

@@ -44,6 +49,7 @@
4449
import org.microg.gms.wearable.channel.OpenChannelCallback;
4550
import org.microg.gms.wearable.proto.AppKey;
4651

52+
import java.io.File;
4753
import java.io.FileNotFoundException;
4854
import java.io.IOException;
4955
import java.util.ArrayList;
@@ -344,8 +350,51 @@ public void run(IWearableCallbacks callbacks) throws RemoteException {
344350

345351
@Override
346352
public void getCompanionPackageForNode(IWearableCallbacks callbacks, String nodeId) throws RemoteException {
347-
Log.d(TAG, "unimplemented Method getCompanionPackageForNode");
353+
Log.d(TAG, "getCompanionPackageForNode: " + nodeId);
348354

355+
postMain(callbacks, () -> {
356+
try {
357+
if (TextUtils.isEmpty(nodeId)) {
358+
Log.e(TAG, "getCompanionPackageForNode: empty nodeId");
359+
callbacks.onGetCompanionPackageForNodeResponse(
360+
new GetCompanionPackageForNodeResponse(CommonStatusCodes.ERROR, ""));
361+
return;
362+
}
363+
364+
if ("cloud".equals(nodeId)) {
365+
Log.d(TAG, "getCompanionPackageForNode: cloud node has no package");
366+
callbacks.onGetCompanionPackageForNodeResponse(
367+
new GetCompanionPackageForNodeResponse(CommonStatusCodes.ERROR, ""));
368+
return;
369+
}
370+
371+
ConnectionConfiguration[] configurations = wearable.getConfigurations();
372+
if (configurations != null) {
373+
for (ConnectionConfiguration config : configurations) {
374+
if (nodeId.equals(config.nodeId) || nodeId.equals(config.peerNodeId)) {
375+
String packageName = config.packageName != null ? config.packageName : "";
376+
Log.d(TAG, "getCompanionPackageForNode: found package " + packageName + " for node " + nodeId);
377+
callbacks.onGetCompanionPackageForNodeResponse(
378+
new GetCompanionPackageForNodeResponse(CommonStatusCodes.SUCCESS, packageName));
379+
return;
380+
}
381+
}
382+
}
383+
384+
Log.w(TAG, "getCompanionPackageForNode: node " + nodeId + " not found");
385+
callbacks.onGetCompanionPackageForNodeResponse(
386+
new GetCompanionPackageForNodeResponse(CommonStatusCodes.ERROR, ""));
387+
388+
} catch (Exception e) {
389+
Log.e(TAG, "getCompanionPackageForNode: exception during processing", e);
390+
try {
391+
callbacks.onGetCompanionPackageForNodeResponse(
392+
new GetCompanionPackageForNodeResponse(CommonStatusCodes.INTERNAL_ERROR, ""));
393+
} catch (RemoteException re) {
394+
Log.w(TAG, "Failed to send error response", re);
395+
}
396+
}
397+
});
349398
}
350399

351400
@Override
@@ -398,18 +447,26 @@ public void setCloudSyncSetting(IWearableCallbacks callbacks, boolean enable) th
398447

399448
@Override
400449
public void getCloudSyncSetting(IWearableCallbacks callbacks) throws RemoteException {
450+
Log.d(TAG, "unimplemented Method: getCloudSyncSetting");
451+
// disabled by default
401452
callbacks.onGetCloudSyncSettingResponse(new GetCloudSyncSettingResponse(0, false));
402453
}
403454

404455
@Override
405456
public void getCloudSyncOptInStatus(IWearableCallbacks callbacks) throws RemoteException {
406457
Log.d(TAG, "unimplemented Method: getCloudSyncOptInStatus");
458+
// opt out by default
407459
callbacks.onGetCloudSyncOptInStatusResponse(new GetCloudSyncOptInStatusResponse(0, false, true));
408460
}
409461

410462
@Override
411-
public void sendRemoteCommand(IWearableCallbacks callbacks, byte b) throws RemoteException {
412-
Log.d(TAG, "unimplemented Method: sendRemoteCommand: " + b);
463+
public void sendAmsRemoteCommand(IWearableCallbacks callbacks, byte command) throws RemoteException {
464+
Log.d(TAG, "unimplemented Method sendAmsRemoteCommand: " + command);
465+
466+
postMain(callbacks, () -> {
467+
// return error, because we dont have AMS handling
468+
callbacks.onStatus(new Status(CommonStatusCodes.INTERNAL_ERROR));
469+
});
413470
}
414471

415472
@Override
@@ -718,12 +775,184 @@ public void removeListener(IWearableCallbacks callbacks, RemoveListenerRequest r
718775

719776
@Override
720777
public void getStorageInformation(IWearableCallbacks callbacks) throws RemoteException {
721-
Log.d(TAG, "unimplemented Method: getStorageInformation");
778+
Log.d(TAG, "getStorageInformation");
779+
postMain(callbacks, () -> {
780+
try {
781+
NodeDatabaseHelper nodeDatabase = wearable.getNodeDatabase();
782+
PackageManager packageManager = context.getPackageManager();
783+
SQLiteDatabase db = nodeDatabase.getReadableDatabase();
784+
785+
File databasePath = context.getDatabasePath("node.db");
786+
long totalDatabaseSize = databasePath != null ? databasePath.length() : 0L;
787+
788+
Map<String, PackageStorageInfo> packageInfoMap = new HashMap<>();
789+
790+
Map<String, String> packageIdToName = new HashMap<>();
791+
Cursor appKeysCursor = db.query("appkeys", new String[]{"_id", "packageName"},
792+
null, null, null, null, null);
793+
794+
while (appKeysCursor.moveToNext()) {
795+
String id = appKeysCursor.getString(0);
796+
String packageName = appKeysCursor.getString(1);
797+
packageIdToName.put(id, packageName);
798+
}
799+
appKeysCursor.close();
800+
801+
for (Map.Entry<String, String> entry : packageIdToName.entrySet()) {
802+
String appKeyId = entry.getKey();
803+
String packageName = entry.getValue();
804+
805+
long dataItemsSize = getTableSizeForAppKey(db, "dataitems", "appkeys_id", appKeyId);
806+
807+
long assetsSize = getAssetsSizeForPackage(db, nodeDatabase, appKeyId);
808+
809+
String appLabel = packageName;
810+
try {
811+
ApplicationInfo appInfo = packageManager.getApplicationInfo(packageName, 0);
812+
CharSequence label = packageManager.getApplicationLabel(appInfo);
813+
if (label != null) {
814+
appLabel = label.toString();
815+
}
816+
} catch (PackageManager.NameNotFoundException e) {
817+
Log.w(TAG, "Package not found: " + packageName);
818+
}
819+
820+
long totalSize = dataItemsSize + assetsSize;
821+
822+
if (totalSize > 0) {
823+
PackageStorageInfo info = new PackageStorageInfo(
824+
packageName,
825+
appLabel,
826+
totalSize
827+
);
828+
packageInfoMap.put(packageName, info);
829+
}
830+
}
831+
832+
List<PackageStorageInfo> packageInfoList = new ArrayList<>(packageInfoMap.values());
833+
PackageStorageInfo[] packageInfoArray = packageInfoList.toArray(
834+
new PackageStorageInfo[packageInfoList.size()]);
835+
836+
StorageInfoResponse response = new StorageInfoResponse(
837+
CommonStatusCodes.SUCCESS,
838+
totalDatabaseSize,
839+
packageInfoArray
840+
);
841+
842+
Log.d(TAG, "getStorageInformation: total db size=" + totalDatabaseSize +
843+
", packages=" + packageInfoArray.length);
844+
callbacks.onStorageInfoResponse(response);
845+
846+
} catch (Exception e) {
847+
Log.e(TAG, "getStorageInformation: exception during processing", e);
848+
try {
849+
callbacks.onStorageInfoResponse(new StorageInfoResponse(
850+
CommonStatusCodes.INTERNAL_ERROR, 0L, new PackageStorageInfo[0]));
851+
} catch (RemoteException re) {
852+
Log.w(TAG, "Failed to send error response", re);
853+
}
854+
}
855+
});
856+
}
857+
858+
private long getTableSizeForAppKey(SQLiteDatabase db, String tableName,
859+
String keyColumn, String appKeyId) {
860+
long totalSize = 0;
861+
862+
Cursor cursor = db.query(tableName, null, keyColumn + "=?",
863+
new String[]{appKeyId}, null, null, null);
864+
865+
int rowCount = cursor.getCount();
866+
cursor.close();
867+
868+
totalSize = rowCount * 1024L;
869+
870+
return totalSize;
871+
}
872+
873+
private long getAssetsSizeForPackage(SQLiteDatabase db, NodeDatabaseHelper nodeDatabase,
874+
String appKeyId) {
875+
long totalSize = 0;
876+
877+
try {
878+
Set<String> assetDigests = new HashSet<>();
879+
Cursor aclCursor = db.query("assetsacls", new String[]{"assets_digest"},
880+
"appkeys_id=?", new String[]{appKeyId}, null, null, null);
881+
882+
while (aclCursor.moveToNext()) {
883+
String digest = aclCursor.getString(0);
884+
assetDigests.add(digest);
885+
}
886+
aclCursor.close();
887+
888+
for (String digest : assetDigests) {
889+
File assetFile = new File(context.getFilesDir(), "assets/" + digest);
890+
if (assetFile.exists()) {
891+
totalSize += assetFile.length();
892+
}
893+
}
894+
} catch (Exception e) {
895+
Log.w(TAG, "Error calculating assets size", e);
896+
}
897+
898+
return totalSize;
722899
}
723900

724901
@Override
725902
public void clearStorage(IWearableCallbacks callbacks) throws RemoteException {
726-
Log.d(TAG, "unimplemented Method: clearStorage");
903+
Log.d(TAG, "clearStorage");
904+
905+
postMain(callbacks, () -> {
906+
try {
907+
Log.d(TAG, "clearStorage: starting storage clear");
908+
909+
NodeDatabaseHelper nodeDatabase = wearable.getNodeDatabase();
910+
SQLiteDatabase db = nodeDatabase.getWritableDatabase();
911+
912+
db.execSQL("DELETE FROM dataitems");
913+
db.execSQL("DELETE FROM assets");
914+
db.execSQL("DELETE FROM assetrefs");
915+
db.execSQL("DELETE FROM assetsacls");
916+
db.execSQL("DELETE FROM nodeinfo");
917+
db.execSQL("DELETE FROM appkeys");
918+
db.execSQL("DELETE FROM archiveDataItems");
919+
db.execSQL("DELETE FROM archiveAssetRefs");
920+
921+
Log.d(TAG, "clearStorage: database tables cleared");
922+
923+
File assetsDir = new File(context.getFilesDir(), "assets");
924+
if (assetsDir.exists() && assetsDir.isDirectory()) {
925+
File[] assetFiles = assetsDir.listFiles();
926+
if (assetFiles != null) {
927+
for (File file : assetFiles) {
928+
if (file.isFile()) {
929+
file.delete();
930+
}
931+
}
932+
}
933+
}
934+
Log.d(TAG, "clearStorage: asset files cleared");
935+
936+
ClockworkNodePreferences prefs = wearable.getClockworkNodePreferences();
937+
if (prefs != null) {
938+
prefs.clear();
939+
}
940+
Log.d(TAG, "clearStorage: preferences cleared");
941+
942+
callbacks.onStatus(Status.SUCCESS);
943+
944+
Log.d(TAG, "clearStorage: complete");
945+
946+
} catch (Exception e) {
947+
Log.e(TAG, "clearStorage: exception during clearing storage", e);
948+
try {
949+
callbacks.onStatus(new Status(CommonStatusCodes.INTERNAL_ERROR));
950+
} catch (RemoteException re) {
951+
Log.w(TAG, "Failed to send error response", re);
952+
}
953+
}
954+
});
955+
727956
}
728957

729958
@Override

play-services-wearable/src/main/aidl/com/google/android/gms/wearable/internal/IWearableService.aidl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ interface IWearableService {
8888
void getCloudSyncSetting(IWearableCallbacks callbacks) = 50;
8989
void getCloudSyncOptInStatus(IWearableCallbacks callbacks) = 51;
9090

91-
void sendRemoteCommand(IWearableCallbacks callbacks, byte b) = 52;
91+
void sendAmsRemoteCommand(IWearableCallbacks callbacks, byte command) = 52;
9292

9393
void getConsentStatus(IWearableCallbacks callbacks) = 64;
9494
void addAccountToConsent(IWearableCallbacks callbacks, in AddAccountToConsentRequest request) = 65;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.google.android.gms.wearable.internal;
2+
3+
import org.microg.safeparcel.AutoSafeParcelable;
4+
import org.microg.safeparcel.SafeParceled;
5+
6+
public class PackageStorageInfo extends AutoSafeParcelable {
7+
@SafeParceled(1)
8+
private final int version = 1;
9+
@SafeParceled(2)
10+
public String packageName;
11+
@SafeParceled(3)
12+
public String appLabel;
13+
@SafeParceled(4)
14+
public long size;
15+
16+
private PackageStorageInfo() {}
17+
18+
public PackageStorageInfo(String packageName, String appLabel, long size) {
19+
this.packageName = packageName;
20+
this.appLabel = appLabel;
21+
this.size = size;
22+
}
23+
24+
public static final Creator<PackageStorageInfo> CREATOR =
25+
new AutoCreator<>(PackageStorageInfo.class);
26+
}

play-services-wearable/src/main/java/com/google/android/gms/wearable/internal/StorageInfoResponse.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,28 @@
1717
package com.google.android.gms.wearable.internal;
1818

1919
import org.microg.safeparcel.AutoSafeParcelable;
20+
import org.microg.safeparcel.SafeParceled;
2021

2122
public class StorageInfoResponse extends AutoSafeParcelable {
22-
public static final Creator<StorageInfoResponse> CREATOR = new AutoCreator<StorageInfoResponse>(StorageInfoResponse.class);
23+
@SafeParceled(1)
24+
private final int version = 1;
25+
@SafeParceled(2)
26+
public int statusCode;
27+
@SafeParceled(3)
28+
public long totalSize;
29+
@SafeParceled(4)
30+
public PackageStorageInfo[] packageStorageInfo;
31+
32+
private StorageInfoResponse() {}
33+
34+
public StorageInfoResponse(int statusCode, long totalSize,
35+
PackageStorageInfo[] packageStorageInfo) {
36+
this.statusCode = statusCode;
37+
this.totalSize = totalSize;
38+
this.packageStorageInfo = packageStorageInfo;
39+
}
40+
41+
public static final Creator<StorageInfoResponse> CREATOR =
42+
new AutoCreator<>(StorageInfoResponse.class);
2343
}
44+

0 commit comments

Comments
 (0)