1 /* 2 * Copyright (C) 2022 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.providers.media.stableuris.dao; 18 19 import android.provider.MediaStore.MediaColumns; 20 21 import com.android.providers.media.util.StringUtils; 22 23 import java.io.IOException; 24 import java.io.Serializable; 25 import java.util.Objects; 26 27 /** 28 * DAO object representing database row of leveldb for volume database backup and recovery. 29 * 30 * Warning: Do not change/modify existing field names as it will affect deserialization of existing 31 * rows. 32 */ 33 public final class BackupIdRow implements Serializable { 34 35 private long mId; 36 private int mIsFavorite; 37 private int mIsPending; 38 private int mIsTrashed; 39 private boolean mIsDirty; 40 41 /** 42 * This is not Owner Package name but a unique identifier to it 43 */ 44 private int mOwnerPackageId; 45 46 /** 47 * Same as {@link MediaColumns#DATE_EXPIRES}. Will be null if media row does not have 48 * expiry time set. 49 */ 50 private String mDateExpires; 51 52 /** 53 * This is required to support cloned user data. 54 */ 55 private int mUserId; 56 private int mMediaType; 57 58 /** 59 * Builder class for {@link BackupIdRow} 60 */ 61 public static class Builder { 62 private long mId; 63 private int mIsFavorite; 64 private int mIsPending; 65 private int mIsTrashed; 66 private boolean mIsDirty; 67 private int mOwnerPackageId; 68 private String mDateExpires; 69 private int mUserId; 70 private int mMediaType; 71 Builder(long id)72 Builder(long id) { 73 this.mId = id; 74 } 75 76 /** 77 * Sets the isFavorite value 78 */ setIsFavorite(int isFavorite)79 public Builder setIsFavorite(int isFavorite) { 80 this.mIsFavorite = isFavorite; 81 return this; 82 } 83 84 /** 85 * Sets the isPending value 86 */ setIsPending(int isPending)87 public Builder setIsPending(int isPending) { 88 this.mIsPending = isPending; 89 return this; 90 } 91 92 /** 93 * Sets the isTrashed value 94 */ setIsTrashed(int isTrashed)95 public Builder setIsTrashed(int isTrashed) { 96 this.mIsTrashed = isTrashed; 97 return this; 98 } 99 100 /** 101 * Sets the ownerPackagedId value 102 */ setOwnerPackagedId(int ownerPackagedId)103 public Builder setOwnerPackagedId(int ownerPackagedId) { 104 this.mOwnerPackageId = ownerPackagedId; 105 return this; 106 } 107 108 /** 109 * Sets the dateExpires value 110 */ setDateExpires(String dateExpires)111 public Builder setDateExpires(String dateExpires) { 112 if (StringUtils.isNullOrEmpty(dateExpires)) { 113 this.mDateExpires = null; 114 } else { 115 long value = Long.parseLong(dateExpires); 116 this.mDateExpires = String.valueOf(value); 117 } 118 119 return this; 120 } 121 122 /** 123 * Sets the userId value 124 */ setUserId(int userId)125 public Builder setUserId(int userId) { 126 this.mUserId = userId; 127 return this; 128 } 129 130 /** 131 * Sets the mediatype value 132 */ setMediaType(int mediaType)133 public Builder setMediaType(int mediaType) { 134 this.mMediaType = mediaType; 135 return this; 136 } 137 138 /** 139 * Sets the isDirty value 140 */ setIsDirty(boolean isDirty)141 public Builder setIsDirty(boolean isDirty) { 142 this.mIsDirty = isDirty; 143 return this; 144 } 145 146 /** 147 * Builds {@link BackupIdRow} object with the given values set 148 */ build()149 public BackupIdRow build() { 150 BackupIdRow backupIdRow = new BackupIdRow(this.mId); 151 backupIdRow.mIsFavorite = this.mIsFavorite; 152 backupIdRow.mIsPending = this.mIsPending; 153 backupIdRow.mIsTrashed = this.mIsTrashed; 154 backupIdRow.mIsDirty = this.mIsDirty; 155 backupIdRow.mOwnerPackageId = this.mOwnerPackageId; 156 backupIdRow.mDateExpires = this.mDateExpires; 157 backupIdRow.mUserId = this.mUserId; 158 backupIdRow.mMediaType = this.mMediaType; 159 160 return backupIdRow; 161 } 162 } 163 newBuilder(long id)164 public static Builder newBuilder(long id) { 165 return new BackupIdRow.Builder(id); 166 } 167 BackupIdRow(long id)168 private BackupIdRow(long id) { 169 this.mId = id; 170 } 171 getId()172 public long getId() { 173 return mId; 174 } 175 getIsFavorite()176 public int getIsFavorite() { 177 return mIsFavorite; 178 } 179 getIsPending()180 public int getIsPending() { 181 return mIsPending; 182 } 183 getIsTrashed()184 public int getIsTrashed() { 185 return mIsTrashed; 186 } 187 getOwnerPackageId()188 public int getOwnerPackageId() { 189 return mOwnerPackageId; 190 } 191 getUserId()192 public int getUserId() { 193 return mUserId; 194 } 195 getDateExpires()196 public String getDateExpires() { 197 return mDateExpires; 198 } 199 getIsDirty()200 public boolean getIsDirty() { 201 return mIsDirty; 202 } 203 getMediaType()204 public int getMediaType() { 205 return mMediaType; 206 } 207 208 /** 209 * Returns human-readable form of {@link BackupIdRow} for easy debugging. 210 */ 211 @Override toString()212 public String toString() { 213 return "BackupIdRow{" + 214 "mId=" + mId + 215 ", mIsFavorite=" + mIsFavorite + 216 ", mIsPending=" + mIsPending + 217 ", mIsTrashed=" + mIsTrashed + 218 ", mIsDirty=" + mIsDirty + 219 ", mOwnerPackageId=" + mOwnerPackageId + 220 ", mDateExpires=" + mDateExpires + 221 ", mUserId=" + mUserId + 222 ", mMediaType=" + mMediaType + 223 '}'; 224 } 225 226 @Override equals(Object o)227 public boolean equals(Object o) { 228 if (this == o) return true; 229 if (!(o instanceof BackupIdRow)) return false; 230 BackupIdRow that = (BackupIdRow) o; 231 return mId == that.mId && mIsFavorite == that.mIsFavorite && mIsPending == that.mIsPending 232 && mIsTrashed == that.mIsTrashed && mIsDirty == that.mIsDirty 233 && mOwnerPackageId == that.mOwnerPackageId && mUserId == that.mUserId 234 && mMediaType == that.mMediaType && Objects.equals(mDateExpires, 235 that.mDateExpires); 236 } 237 238 @Override hashCode()239 public int hashCode() { 240 return Objects.hash(mId, mIsFavorite, mIsPending, mIsTrashed, mIsDirty, mOwnerPackageId, 241 mDateExpires, mUserId, mMediaType); 242 } 243 244 /** 245 * Serializes the given {@link BackupIdRow} object to a string 246 * Format is 247 * "is_dirty::_id::is_fav::is_pending::is_trashed::media_type::user_id::owner_id::date_expires" 248 */ serialize(BackupIdRow backupIdRow)249 public static String serialize(BackupIdRow backupIdRow) throws IOException { 250 return String.format("%s::%s::%s::%s::%s::%s::%s::%s::%s", 251 backupIdRow.getIsDirty() ? "1" : "0", backupIdRow.getId(), 252 backupIdRow.getIsFavorite(), backupIdRow.getIsPending(), backupIdRow.getIsTrashed(), 253 backupIdRow.getMediaType(), backupIdRow.getUserId(), 254 backupIdRow.getOwnerPackageId(), backupIdRow.getDateExpires()); 255 } 256 257 /** 258 * Deserializes the given string to {@link BackupIdRow} object 259 */ deserialize(String s)260 public static BackupIdRow deserialize(String s) throws IOException, ClassNotFoundException { 261 if (s == null || s.isEmpty()) { 262 return null; 263 } 264 265 String[] fields = s.split("::"); 266 BackupIdRow.Builder builder = BackupIdRow.newBuilder(Long.parseLong(fields[1])); 267 builder.setIsDirty(Objects.equals(fields[0], "1")); 268 builder.setIsFavorite(Integer.parseInt(fields[2])); 269 builder.setIsPending(Integer.parseInt(fields[3])); 270 builder.setIsTrashed(Integer.parseInt(fields[4])); 271 builder.setMediaType(Integer.parseInt(fields[5])); 272 builder.setUserId(Integer.parseInt(fields[6])); 273 builder.setOwnerPackagedId(Integer.parseInt(fields[7])); 274 builder.setDateExpires(fields[8]); 275 return builder.build(); 276 } 277 } 278