Loading play-services-core/src/main/java/org/microg/gms/wearable/DataItemRecord.java +38 −1 Original line number Diff line number Diff line Loading @@ -27,8 +27,12 @@ import com.google.android.gms.wearable.internal.DataItemParcelable; import org.microg.wearable.proto.AssetEntry; import org.microg.wearable.proto.SetDataItem; import java.util.ArrayList; import java.util.List; import java.util.Map; import okio.ByteString; public class DataItemRecord { public DataItemInternal dataItem; public String source; Loading Loading @@ -67,6 +71,30 @@ public class DataItemRecord { return parcelable; } public SetDataItem toSetDataItem() { SetDataItem.Builder builder = new SetDataItem.Builder() .packageName(packageName) .signatureDigest(signatureDigest) .uri(dataItem.uri.toString()) .seqId(seqId) .deleted(deleted) .lastModified(lastModified); if (source != null) builder.source(source); if (dataItem.data != null) builder.data(ByteString.of(dataItem.data)); List<AssetEntry> protoAssets = new ArrayList<AssetEntry>(); Map<String, Asset> assets = dataItem.getAssets(); for (String key : assets.keySet()) { protoAssets.add(new AssetEntry.Builder() .key(key) .unknown3(4) .value(new org.microg.wearable.proto.Asset.Builder() .digest(assets.get(key).getDigest()) .build()).build()); } builder.assets(protoAssets); return builder.build(); } public static DataItemRecord fromCursor(Cursor cursor) { DataItemRecord record = new DataItemRecord(); record.packageName = cursor.getString(1); Loading @@ -78,6 +106,15 @@ public class DataItemRecord { record.dataItem.data = cursor.getBlob(8); record.lastModified = cursor.getLong(9); record.assetsAreReady = cursor.getLong(10) > 0; if (cursor.getString(11) != null) { record.dataItem.addAsset(cursor.getString(11), Asset.createFromRef(cursor.getString(12))); while (cursor.moveToNext()) { if (cursor.getLong(5) == record.seqId) { record.dataItem.addAsset(cursor.getString(11), Asset.createFromRef(cursor.getString(12))); } } cursor.moveToPrevious(); } return record; } Loading @@ -87,7 +124,7 @@ public class DataItemRecord { if (setDataItem.data != null) record.dataItem.data = setDataItem.data.toByteArray(); if (setDataItem.assets != null) { for (AssetEntry asset : setDataItem.assets) { // TODO record.dataItem.addAsset(asset.key, asset.value) record.dataItem.addAsset(asset.key, Asset.createFromRef(asset.value.digest)); } } record.source = setDataItem.source; Loading play-services-core/src/main/java/org/microg/gms/wearable/MessageHandler.java +9 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package org.microg.gms.wearable; import android.text.TextUtils; import android.util.Log; import com.google.android.gms.wearable.Asset; import com.google.android.gms.wearable.ConnectionConfiguration; import com.google.android.gms.wearable.internal.MessageEventParcelable; import com.google.android.gms.wearable.internal.NodeParcelable; Loading Loading @@ -86,6 +87,13 @@ public class MessageHandler extends ServerMessageListener { @Override public void onSetAsset(SetAsset setAsset) { Log.d(TAG, "onSetAsset: " + setAsset); Asset asset; if (setAsset.data != null) { asset = Asset.createFromBytes(setAsset.data.toByteArray()); } else { asset = Asset.createFromRef(setAsset.digest); } service.addAssetToDatabase(asset, setAsset.appkeys.appKeys); } @Override Loading Loading @@ -149,6 +157,7 @@ public class MessageHandler extends ServerMessageListener { @Override public void onFilePiece(FilePiece filePiece) { Log.d(TAG, "onFilePiece: " + filePiece); service.handleFilePiece(getConnection(), filePiece.fileName, filePiece.piece.toByteArray(), filePiece.finalPiece ? filePiece.digest : null); } @Override Loading play-services-core/src/main/java/org/microg/gms/wearable/NodeDatabaseHelper.java +18 −2 Original line number Diff line number Diff line Loading @@ -143,7 +143,7 @@ public class NodeDatabaseHelper extends SQLiteOpenHelper { } private static void updateRecord(SQLiteDatabase db, String key, DataItemRecord record) { Log.d(TAG, "updateRecord not implemented: " + record); Log.d(TAG, "updateRecord no: " + record); } private String insertRecord(SQLiteDatabase db, DataItemRecord record) { Loading Loading @@ -220,8 +220,24 @@ public class NodeDatabaseHelper extends SQLiteOpenHelper { if (cursor.moveToFirst()) { res = cursor.getLong(0); } cursor.close();; cursor.close(); } return res; } public void putAsset(Asset asset, boolean dataPresent) { ContentValues cv = new ContentValues(); cv.put("digest", asset.getDigest()); cv.put("dataPresent", dataPresent ? 1 : 0); cv.put("timestampMs", System.currentTimeMillis()); getWritableDatabase().insert("assets", null, cv); } public void allowAssetAccess(String digest, String packageName, String signatureDigest) { SQLiteDatabase db = getWritableDatabase(); ContentValues cv = new ContentValues(); cv.put("assets_digest", digest); cv.put("appkeys_it", getAppKey(db, packageName, signatureDigest)); db.insert("assetsacls", null, cv); } } play-services-core/src/main/java/org/microg/gms/wearable/WearableServiceImpl.java +93 −25 Original line number Diff line number Diff line Loading @@ -53,17 +53,23 @@ import com.google.android.gms.wearable.internal.PutDataResponse; import com.google.android.gms.wearable.internal.RemoveListenerRequest; import org.microg.gms.common.PackageUtils; import org.microg.gms.common.Utils; import org.microg.wearable.WearableConnection; import org.microg.wearable.proto.AssetEntry; import org.microg.wearable.proto.AckAsset; import org.microg.wearable.proto.AppKey; import org.microg.wearable.proto.AppKeys; import org.microg.wearable.proto.FilePiece; import org.microg.wearable.proto.RootMessage; import org.microg.wearable.proto.SetDataItem; import org.microg.wearable.proto.SetAsset; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; Loading Loading @@ -129,12 +135,13 @@ public class WearableServiceImpl extends IWearableService.Stub implements IWeara for (Map.Entry<String, Asset> assetEntry : request.getAssets().entrySet()) { Asset asset = prepareAsset(packageName, assetEntry.getValue()); if (asset != null) { nodeDatabase.putAsset(asset, true); dataItem.addAsset(assetEntry.getKey(), asset); } } dataItem.data = request.getData(); DataItemParcelable parcelable = putDataItem(packageName, PackageUtils.firstSignatureDigest(context, packageName), getLocalNodeId(), dataItem).toParcelable(); DataItemParcelable parcelable = putDataItem(packageName, PackageUtils.firstSignatureDigest(context, packageName), getLocalNodeId(), dataItem).toParcelable(); callbacks.onPutDataResponse(new PutDataResponse(0, parcelable)); } Loading @@ -156,6 +163,13 @@ public class WearableServiceImpl extends IWearableService.Stub implements IWeara } private Asset prepareAsset(String packageName, Asset asset) { if (asset.getFd() != null && asset.data == null) { try { asset.data = Utils.readStreamToEnd(new FileInputStream(asset.getFd().getFileDescriptor())); } catch (IOException e) { Log.w(TAG, e); } } if (asset.data != null) { String digest = calculateDigest(asset.data); File assetFile = createAssetFile(digest); Loading Loading @@ -188,6 +202,12 @@ public class WearableServiceImpl extends IWearableService.Stub implements IWeara return new File(dir, digest + ".asset"); } private File createAssetReceiveTempFile(String name) { File dir = new File(context.getFilesDir(), "piece"); dir.mkdirs(); return new File(dir, name); } private String calculateDigest(byte[] data) { try { return Base64.encodeToString(MessageDigest.getInstance("SHA1").digest(data), Base64.NO_WRAP | Base64.NO_PADDING | Base64.URL_SAFE); Loading Loading @@ -480,29 +500,13 @@ public class WearableServiceImpl extends IWearableService.Stub implements IWeara if (cursor != null) { while (cursor.moveToNext()) { DataItemRecord record = DataItemRecord.fromCursor(cursor); for (Asset asset : record.dataItem.getAssets().values()) { syncAssetToPeer(connection, record, asset); } Log.d(TAG, "Sync over " + connection + ": " + record); SetDataItem.Builder builder = new SetDataItem.Builder() .packageName(record.packageName) .signatureDigest(record.signatureDigest) .uri(record.dataItem.uri.toString()) .seqId(record.seqId) .deleted(record.deleted) .lastModified(record.lastModified); if (record.source != null) builder.source(record.source); if (record.dataItem.data != null) builder.data(ByteString.of(record.dataItem.data)); List<AssetEntry> protoAssets = new ArrayList<AssetEntry>(); Map<String, Asset> assets = record.dataItem.getAssets(); for (String key : assets.keySet()) { protoAssets.add(new AssetEntry.Builder() .key(key) .unknown3(4) .value(new org.microg.wearable.proto.Asset.Builder() .digest(assets.get(key).getDigest()) .build()).build()); } builder.assets(protoAssets); try { connection.writeMessage(new RootMessage.Builder().setDataItem(builder.build()).build()); connection.writeMessage(new RootMessage.Builder().setDataItem(record.toSetDataItem()).build()); } catch (IOException e) { Log.w(TAG, e); break; Loading @@ -513,7 +517,71 @@ public class WearableServiceImpl extends IWearableService.Stub implements IWeara Log.d(TAG, "-- Done syncing over " + connection + ", nodeId " + nodeId + " starting with seqId " + seqId); } private void syncAssetToPeer(WearableConnection connection, DataItemRecord record, Asset asset) { try { Log.d(TAG, "Sync over " + connection + ": " + asset); connection.writeMessage(new RootMessage.Builder().setAsset( new SetAsset.Builder() .digest(asset.getDigest()) .appkeys(new AppKeys(Collections.singletonList(new AppKey(record.packageName, record.signatureDigest)))) .build()).unknown13(true).build()); File assetFile = createAssetFile(asset.getDigest()); String fileName = calculateDigest(assetFile.toString().getBytes()); FileInputStream fis = new FileInputStream(assetFile); byte[] arr = new byte[12215]; ByteString lastPiece = null; int c = 0; while ((c = fis.read(arr)) > 0) { if (lastPiece != null) { Log.d(TAG, "Sync over " + connection + ": Asset piece for fileName " + fileName + ": " + lastPiece); connection.writeMessage(new RootMessage.Builder().filePiece(new FilePiece(fileName, false, lastPiece, null)).build()); } lastPiece = ByteString.of(arr, 0, c); } Log.d(TAG, "Sync over " + connection + ": Last asset piece for fileName " + fileName + ": " + lastPiece); connection.writeMessage(new RootMessage.Builder().filePiece(new FilePiece(fileName, true, lastPiece, asset.getDigest())).build()); } catch (IOException e) { Log.w(TAG, e); } } public void addAssetToDatabase(Asset asset, List<AppKey> appKeys) { nodeDatabase.putAsset(asset, false); for (AppKey appKey : appKeys) { nodeDatabase.allowAssetAccess(asset.getDigest(), appKey.packageName, appKey.signatureDigest); } } public long getCurrentSeqId(String nodeId) { return nodeDatabase.getCurrentSeqId(nodeId); } public void handleFilePiece(WearableConnection connection, String fileName, byte[] bytes, String finalPieceDigest) { File file = createAssetReceiveTempFile(fileName); try { FileOutputStream fos = new FileOutputStream(file, true); fos.write(bytes); fos.close(); } catch (IOException e) { Log.w(TAG, e); } if (finalPieceDigest != null) { // This is a final piece. If digest matches we're so happy! try { String digest = calculateDigest(Utils.readStreamToEnd(new FileInputStream(file))); if (digest.equals(finalPieceDigest)) { if (file.renameTo(createAssetFile(digest))) { // TODO: Mark as stored in db connection.writeMessage(new RootMessage.Builder().ackAsset(new AckAsset(digest)).build()); } else { Log.w(TAG, "Could not rename to target file name. delete=" + file.delete()); } } else { Log.w(TAG, "Received digest does not match. delete=" + file.delete()); } } catch (IOException e) { Log.w(TAG, "Failed working with temp file. delete=" + file.delete(), e); } } } } Loading
play-services-core/src/main/java/org/microg/gms/wearable/DataItemRecord.java +38 −1 Original line number Diff line number Diff line Loading @@ -27,8 +27,12 @@ import com.google.android.gms.wearable.internal.DataItemParcelable; import org.microg.wearable.proto.AssetEntry; import org.microg.wearable.proto.SetDataItem; import java.util.ArrayList; import java.util.List; import java.util.Map; import okio.ByteString; public class DataItemRecord { public DataItemInternal dataItem; public String source; Loading Loading @@ -67,6 +71,30 @@ public class DataItemRecord { return parcelable; } public SetDataItem toSetDataItem() { SetDataItem.Builder builder = new SetDataItem.Builder() .packageName(packageName) .signatureDigest(signatureDigest) .uri(dataItem.uri.toString()) .seqId(seqId) .deleted(deleted) .lastModified(lastModified); if (source != null) builder.source(source); if (dataItem.data != null) builder.data(ByteString.of(dataItem.data)); List<AssetEntry> protoAssets = new ArrayList<AssetEntry>(); Map<String, Asset> assets = dataItem.getAssets(); for (String key : assets.keySet()) { protoAssets.add(new AssetEntry.Builder() .key(key) .unknown3(4) .value(new org.microg.wearable.proto.Asset.Builder() .digest(assets.get(key).getDigest()) .build()).build()); } builder.assets(protoAssets); return builder.build(); } public static DataItemRecord fromCursor(Cursor cursor) { DataItemRecord record = new DataItemRecord(); record.packageName = cursor.getString(1); Loading @@ -78,6 +106,15 @@ public class DataItemRecord { record.dataItem.data = cursor.getBlob(8); record.lastModified = cursor.getLong(9); record.assetsAreReady = cursor.getLong(10) > 0; if (cursor.getString(11) != null) { record.dataItem.addAsset(cursor.getString(11), Asset.createFromRef(cursor.getString(12))); while (cursor.moveToNext()) { if (cursor.getLong(5) == record.seqId) { record.dataItem.addAsset(cursor.getString(11), Asset.createFromRef(cursor.getString(12))); } } cursor.moveToPrevious(); } return record; } Loading @@ -87,7 +124,7 @@ public class DataItemRecord { if (setDataItem.data != null) record.dataItem.data = setDataItem.data.toByteArray(); if (setDataItem.assets != null) { for (AssetEntry asset : setDataItem.assets) { // TODO record.dataItem.addAsset(asset.key, asset.value) record.dataItem.addAsset(asset.key, Asset.createFromRef(asset.value.digest)); } } record.source = setDataItem.source; Loading
play-services-core/src/main/java/org/microg/gms/wearable/MessageHandler.java +9 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package org.microg.gms.wearable; import android.text.TextUtils; import android.util.Log; import com.google.android.gms.wearable.Asset; import com.google.android.gms.wearable.ConnectionConfiguration; import com.google.android.gms.wearable.internal.MessageEventParcelable; import com.google.android.gms.wearable.internal.NodeParcelable; Loading Loading @@ -86,6 +87,13 @@ public class MessageHandler extends ServerMessageListener { @Override public void onSetAsset(SetAsset setAsset) { Log.d(TAG, "onSetAsset: " + setAsset); Asset asset; if (setAsset.data != null) { asset = Asset.createFromBytes(setAsset.data.toByteArray()); } else { asset = Asset.createFromRef(setAsset.digest); } service.addAssetToDatabase(asset, setAsset.appkeys.appKeys); } @Override Loading Loading @@ -149,6 +157,7 @@ public class MessageHandler extends ServerMessageListener { @Override public void onFilePiece(FilePiece filePiece) { Log.d(TAG, "onFilePiece: " + filePiece); service.handleFilePiece(getConnection(), filePiece.fileName, filePiece.piece.toByteArray(), filePiece.finalPiece ? filePiece.digest : null); } @Override Loading
play-services-core/src/main/java/org/microg/gms/wearable/NodeDatabaseHelper.java +18 −2 Original line number Diff line number Diff line Loading @@ -143,7 +143,7 @@ public class NodeDatabaseHelper extends SQLiteOpenHelper { } private static void updateRecord(SQLiteDatabase db, String key, DataItemRecord record) { Log.d(TAG, "updateRecord not implemented: " + record); Log.d(TAG, "updateRecord no: " + record); } private String insertRecord(SQLiteDatabase db, DataItemRecord record) { Loading Loading @@ -220,8 +220,24 @@ public class NodeDatabaseHelper extends SQLiteOpenHelper { if (cursor.moveToFirst()) { res = cursor.getLong(0); } cursor.close();; cursor.close(); } return res; } public void putAsset(Asset asset, boolean dataPresent) { ContentValues cv = new ContentValues(); cv.put("digest", asset.getDigest()); cv.put("dataPresent", dataPresent ? 1 : 0); cv.put("timestampMs", System.currentTimeMillis()); getWritableDatabase().insert("assets", null, cv); } public void allowAssetAccess(String digest, String packageName, String signatureDigest) { SQLiteDatabase db = getWritableDatabase(); ContentValues cv = new ContentValues(); cv.put("assets_digest", digest); cv.put("appkeys_it", getAppKey(db, packageName, signatureDigest)); db.insert("assetsacls", null, cv); } }
play-services-core/src/main/java/org/microg/gms/wearable/WearableServiceImpl.java +93 −25 Original line number Diff line number Diff line Loading @@ -53,17 +53,23 @@ import com.google.android.gms.wearable.internal.PutDataResponse; import com.google.android.gms.wearable.internal.RemoveListenerRequest; import org.microg.gms.common.PackageUtils; import org.microg.gms.common.Utils; import org.microg.wearable.WearableConnection; import org.microg.wearable.proto.AssetEntry; import org.microg.wearable.proto.AckAsset; import org.microg.wearable.proto.AppKey; import org.microg.wearable.proto.AppKeys; import org.microg.wearable.proto.FilePiece; import org.microg.wearable.proto.RootMessage; import org.microg.wearable.proto.SetDataItem; import org.microg.wearable.proto.SetAsset; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; Loading Loading @@ -129,12 +135,13 @@ public class WearableServiceImpl extends IWearableService.Stub implements IWeara for (Map.Entry<String, Asset> assetEntry : request.getAssets().entrySet()) { Asset asset = prepareAsset(packageName, assetEntry.getValue()); if (asset != null) { nodeDatabase.putAsset(asset, true); dataItem.addAsset(assetEntry.getKey(), asset); } } dataItem.data = request.getData(); DataItemParcelable parcelable = putDataItem(packageName, PackageUtils.firstSignatureDigest(context, packageName), getLocalNodeId(), dataItem).toParcelable(); DataItemParcelable parcelable = putDataItem(packageName, PackageUtils.firstSignatureDigest(context, packageName), getLocalNodeId(), dataItem).toParcelable(); callbacks.onPutDataResponse(new PutDataResponse(0, parcelable)); } Loading @@ -156,6 +163,13 @@ public class WearableServiceImpl extends IWearableService.Stub implements IWeara } private Asset prepareAsset(String packageName, Asset asset) { if (asset.getFd() != null && asset.data == null) { try { asset.data = Utils.readStreamToEnd(new FileInputStream(asset.getFd().getFileDescriptor())); } catch (IOException e) { Log.w(TAG, e); } } if (asset.data != null) { String digest = calculateDigest(asset.data); File assetFile = createAssetFile(digest); Loading Loading @@ -188,6 +202,12 @@ public class WearableServiceImpl extends IWearableService.Stub implements IWeara return new File(dir, digest + ".asset"); } private File createAssetReceiveTempFile(String name) { File dir = new File(context.getFilesDir(), "piece"); dir.mkdirs(); return new File(dir, name); } private String calculateDigest(byte[] data) { try { return Base64.encodeToString(MessageDigest.getInstance("SHA1").digest(data), Base64.NO_WRAP | Base64.NO_PADDING | Base64.URL_SAFE); Loading Loading @@ -480,29 +500,13 @@ public class WearableServiceImpl extends IWearableService.Stub implements IWeara if (cursor != null) { while (cursor.moveToNext()) { DataItemRecord record = DataItemRecord.fromCursor(cursor); for (Asset asset : record.dataItem.getAssets().values()) { syncAssetToPeer(connection, record, asset); } Log.d(TAG, "Sync over " + connection + ": " + record); SetDataItem.Builder builder = new SetDataItem.Builder() .packageName(record.packageName) .signatureDigest(record.signatureDigest) .uri(record.dataItem.uri.toString()) .seqId(record.seqId) .deleted(record.deleted) .lastModified(record.lastModified); if (record.source != null) builder.source(record.source); if (record.dataItem.data != null) builder.data(ByteString.of(record.dataItem.data)); List<AssetEntry> protoAssets = new ArrayList<AssetEntry>(); Map<String, Asset> assets = record.dataItem.getAssets(); for (String key : assets.keySet()) { protoAssets.add(new AssetEntry.Builder() .key(key) .unknown3(4) .value(new org.microg.wearable.proto.Asset.Builder() .digest(assets.get(key).getDigest()) .build()).build()); } builder.assets(protoAssets); try { connection.writeMessage(new RootMessage.Builder().setDataItem(builder.build()).build()); connection.writeMessage(new RootMessage.Builder().setDataItem(record.toSetDataItem()).build()); } catch (IOException e) { Log.w(TAG, e); break; Loading @@ -513,7 +517,71 @@ public class WearableServiceImpl extends IWearableService.Stub implements IWeara Log.d(TAG, "-- Done syncing over " + connection + ", nodeId " + nodeId + " starting with seqId " + seqId); } private void syncAssetToPeer(WearableConnection connection, DataItemRecord record, Asset asset) { try { Log.d(TAG, "Sync over " + connection + ": " + asset); connection.writeMessage(new RootMessage.Builder().setAsset( new SetAsset.Builder() .digest(asset.getDigest()) .appkeys(new AppKeys(Collections.singletonList(new AppKey(record.packageName, record.signatureDigest)))) .build()).unknown13(true).build()); File assetFile = createAssetFile(asset.getDigest()); String fileName = calculateDigest(assetFile.toString().getBytes()); FileInputStream fis = new FileInputStream(assetFile); byte[] arr = new byte[12215]; ByteString lastPiece = null; int c = 0; while ((c = fis.read(arr)) > 0) { if (lastPiece != null) { Log.d(TAG, "Sync over " + connection + ": Asset piece for fileName " + fileName + ": " + lastPiece); connection.writeMessage(new RootMessage.Builder().filePiece(new FilePiece(fileName, false, lastPiece, null)).build()); } lastPiece = ByteString.of(arr, 0, c); } Log.d(TAG, "Sync over " + connection + ": Last asset piece for fileName " + fileName + ": " + lastPiece); connection.writeMessage(new RootMessage.Builder().filePiece(new FilePiece(fileName, true, lastPiece, asset.getDigest())).build()); } catch (IOException e) { Log.w(TAG, e); } } public void addAssetToDatabase(Asset asset, List<AppKey> appKeys) { nodeDatabase.putAsset(asset, false); for (AppKey appKey : appKeys) { nodeDatabase.allowAssetAccess(asset.getDigest(), appKey.packageName, appKey.signatureDigest); } } public long getCurrentSeqId(String nodeId) { return nodeDatabase.getCurrentSeqId(nodeId); } public void handleFilePiece(WearableConnection connection, String fileName, byte[] bytes, String finalPieceDigest) { File file = createAssetReceiveTempFile(fileName); try { FileOutputStream fos = new FileOutputStream(file, true); fos.write(bytes); fos.close(); } catch (IOException e) { Log.w(TAG, e); } if (finalPieceDigest != null) { // This is a final piece. If digest matches we're so happy! try { String digest = calculateDigest(Utils.readStreamToEnd(new FileInputStream(file))); if (digest.equals(finalPieceDigest)) { if (file.renameTo(createAssetFile(digest))) { // TODO: Mark as stored in db connection.writeMessage(new RootMessage.Builder().ackAsset(new AckAsset(digest)).build()); } else { Log.w(TAG, "Could not rename to target file name. delete=" + file.delete()); } } else { Log.w(TAG, "Received digest does not match. delete=" + file.delete()); } } catch (IOException e) { Log.w(TAG, "Failed working with temp file. delete=" + file.delete(), e); } } } }