1 /* 2 * Copyright (C) 2024 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 com.android.settingslib.datastore 18 19 import androidx.annotation.IntDef 20 import java.io.InputStream 21 import java.io.OutputStream 22 import java.util.zip.Deflater 23 import java.util.zip.DeflaterOutputStream 24 import java.util.zip.InflaterInputStream 25 26 /** Unique id of the codec. */ 27 @Target(AnnotationTarget.TYPE) 28 @IntDef( 29 BackupCodecId.NO_OP.toInt(), 30 BackupCodecId.ZIP.toInt(), 31 ) 32 @Retention(AnnotationRetention.SOURCE) 33 annotation class BackupCodecId { 34 companion object { 35 /** Unknown reason of the change. */ 36 const val NO_OP: Byte = 0 37 /** Data is updated. */ 38 const val ZIP: Byte = 1 39 } 40 } 41 42 /** How to encode/decode the backup data. */ 43 interface BackupCodec { 44 /** Unique id of the codec. */ 45 val id: @BackupCodecId Byte 46 47 /** Name of the codec. */ 48 val name: String 49 50 /** Encodes the backup data. */ encodenull51 fun encode(outputStream: OutputStream): OutputStream 52 53 /** Decodes the backup data. */ 54 fun decode(inputStream: InputStream): InputStream 55 56 companion object { 57 @JvmStatic 58 fun fromId(id: @BackupCodecId Byte): BackupCodec = 59 when (id) { 60 BackupCodecId.NO_OP -> BackupNoOpCodec() 61 BackupCodecId.ZIP -> BackupZipCodec.BEST_COMPRESSION 62 else -> throw IllegalArgumentException("Unknown codec id $id") 63 } 64 } 65 } 66 67 /** Codec without any additional encoding/decoding. */ 68 class BackupNoOpCodec : BackupCodec { 69 override val id 70 get() = BackupCodecId.NO_OP 71 72 override val name 73 get() = "N/A" 74 encodenull75 override fun encode(outputStream: OutputStream) = outputStream 76 77 override fun decode(inputStream: InputStream) = inputStream 78 } 79 80 /** Codec with ZIP compression. */ 81 class BackupZipCodec( 82 private val compressionLevel: Int, 83 override val name: String, 84 ) : BackupCodec { 85 override val id 86 get() = BackupCodecId.ZIP 87 88 override fun encode(outputStream: OutputStream) = 89 DeflaterOutputStream(outputStream, Deflater(compressionLevel)) 90 91 override fun decode(inputStream: InputStream) = InflaterInputStream(inputStream) 92 93 companion object { 94 val DEFAULT_COMPRESSION = BackupZipCodec(Deflater.DEFAULT_COMPRESSION, "ZipDefault") 95 val BEST_COMPRESSION = BackupZipCodec(Deflater.BEST_COMPRESSION, "ZipBestCompression") 96 val BEST_SPEED = BackupZipCodec(Deflater.BEST_SPEED, "ZipBestSpeed") 97 } 98 } 99