/* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settingslib.graph import android.os.Bundle import com.android.settingslib.graph.proto.PreferenceProto import com.android.settingslib.ipc.MessageCodec import com.android.settingslib.metadata.PreferenceCoordinate import com.android.settingslib.metadata.useParcel import java.util.Arrays /** Message codec for [PreferenceGetterRequest]. */ class PreferenceGetterRequestCodec : MessageCodec { override fun encode(data: PreferenceGetterRequest) = Bundle(2).apply { putParcelableArray(null, data.preferences) putInt(FLAGS, data.flags) } @Suppress("DEPRECATION") override fun decode(data: Bundle): PreferenceGetterRequest { data.classLoader = PreferenceCoordinate::class.java.classLoader val array = data.getParcelableArray(null)!! return PreferenceGetterRequest( Arrays.copyOf(array, array.size, Array::class.java), data.getInt(FLAGS), ) } companion object { private const val FLAGS = "f" } } /** Message codec for [PreferenceGetterResponse]. */ class PreferenceGetterResponseCodec : MessageCodec { override fun encode(data: PreferenceGetterResponse) = Bundle(2).apply { data.errors.toErrorsByteArray()?.let { putByteArray(ERRORS, it) } data.preferences.toPreferencesByteArray()?.let { putByteArray(null, it) } } private fun Map.toErrorsByteArray(): ByteArray? { if (isEmpty()) return null return useParcel { parcel -> parcel.writeInt(size) for ((coordinate, code) in this) { coordinate.writeToParcel(parcel, 0) parcel.writeInt(code) } parcel.marshall() } } private fun Map.toPreferencesByteArray(): ByteArray? { if (isEmpty()) return null return useParcel { parcel -> parcel.writeInt(size) for ((coordinate, preferenceProto) in this) { coordinate.writeToParcel(parcel, 0) val data = preferenceProto.toByteArray() parcel.writeInt(data.size) parcel.writeByteArray(data) } parcel.marshall() } } override fun decode(data: Bundle) = PreferenceGetterResponse( data.getByteArray(ERRORS).toErrors(), data.getByteArray(null).toPreferences(), ) private fun ByteArray?.toErrors(): Map { if (this == null) return emptyMap() return useParcel { parcel -> parcel.unmarshall(this, 0, size) parcel.setDataPosition(0) val count = parcel.readInt() val errors = mutableMapOf() repeat(count) { val coordinate = PreferenceCoordinate(parcel) errors[coordinate] = parcel.readInt() } errors } } private fun ByteArray?.toPreferences(): Map { if (this == null) return emptyMap() return useParcel { parcel -> parcel.unmarshall(this, 0, size) parcel.setDataPosition(0) val count = parcel.readInt() val preferences = mutableMapOf() repeat(count) { val coordinate = PreferenceCoordinate(parcel) val bytes = parcel.readInt() val array = ByteArray(bytes).also { parcel.readByteArray(it) } preferences[coordinate] = PreferenceProto.parseFrom(array) } preferences } } companion object { private const val ERRORS = "e" } }