blob: dbe820ab20f263523fabd0f842f0dca7bbd52646 [file] [log] [blame]
/*
* Copyright (C) 2022 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.clockwork.displayoffload;
import static com.android.clockwork.displayoffload.Utils.TAG;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_ARC_SHAPE_RESOURCE;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_BINARY_OPERATION;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_BITMAP_RESOURCE;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_CUSTOM_RESOURCE;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_DYNAMIC_TEXT;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_LINE_SHAPE_RESOURCE;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_MAPPING_LINEAR;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_MAPPING_MODULO;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_MAPPING_NUMBER_FORMAT;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_MAPPING_RANGE;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_MINUTES_VALID;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_OFFLOAD_CONSTANT;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_OFFLOAD_METRIC;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_OFFLOAD_RAW_METRIC;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_OFFLOAD_STRING;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_RECT_SHAPE_RESOURCE;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_ROTATION_GROUP;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_ROUND_RECT_SHAPE_RESOURCE;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_SPRITE_SHEET_PNG_RESOURCE;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_STATIC_TEXT;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_STRING_RESOURCE;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_TERNARY_OPERATION;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_TRANSLATION_GROUP;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_TTF_FONT_RESOURCE;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.FIELD_UNARY_OPERATION;
import static com.google.android.clockwork.ambient.offload.IDisplayOffloadService.RESOURCE_ID_EMPTY_LAYOUT;
import android.os.Bundle;
import android.util.Log;
import com.android.clockwork.displayoffload.HalTypeConverter.HalTypeConverterSupplier;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.google.android.clockwork.ambient.offload.types.ArcPathResource;
import com.google.android.clockwork.ambient.offload.types.BinaryOperation;
import com.google.android.clockwork.ambient.offload.types.BitmapResource;
import com.google.android.clockwork.ambient.offload.types.CustomResource;
import com.google.android.clockwork.ambient.offload.types.DynamicTextResource;
import com.google.android.clockwork.ambient.offload.types.LineShapeResource;
import com.google.android.clockwork.ambient.offload.types.LinearMetricMapping;
import com.google.android.clockwork.ambient.offload.types.ModuloMapping;
import com.google.android.clockwork.ambient.offload.types.NumberFormatMapping;
import com.google.android.clockwork.ambient.offload.types.OffloadConstant;
import com.google.android.clockwork.ambient.offload.types.OffloadMetric;
import com.google.android.clockwork.ambient.offload.types.OffloadRawMetric;
import com.google.android.clockwork.ambient.offload.types.OffloadString;
import com.google.android.clockwork.ambient.offload.types.RangeMapping;
import com.google.android.clockwork.ambient.offload.types.RectShapeResource;
import com.google.android.clockwork.ambient.offload.types.RotationGroup;
import com.google.android.clockwork.ambient.offload.types.RoundRectShapeResource;
import com.google.android.clockwork.ambient.offload.types.SpriteSheetPngResource;
import com.google.android.clockwork.ambient.offload.types.StaticTextResource;
import com.google.android.clockwork.ambient.offload.types.StringResource;
import com.google.android.clockwork.ambient.offload.types.TernaryOperation;
import com.google.android.clockwork.ambient.offload.types.TranslationGroup;
import com.google.android.clockwork.ambient.offload.types.TtfFontResource;
import com.google.android.clockwork.ambient.offload.types.UnaryOperation;
import java.util.ArrayList;
import java.util.List;
public abstract class BaseOffloadLayout {
@VisibleForTesting
protected final HalResourceStore mHalResourceStore;
protected final HalTypeConverterSupplier mHalTypeConverter;
protected final TextPreprocessor mTextPreprocessor;
// LINT.IfChange(offload_type_fields)
// Aidl types
protected final List<CustomResource> mCustomResources = new ArrayList<>();
protected final List<RotationGroup> mRotationGroups = new ArrayList<>();
protected final List<TranslationGroup> mTranslationGroups = new ArrayList<>();
protected final List<BitmapResource> mBitmapResources = new ArrayList<>();
protected final List<ArcPathResource> mArcPathResources = new ArrayList<>();
protected final List<RectShapeResource> mRectShapeResources = new ArrayList<>();
protected final List<RoundRectShapeResource> mRoundRectShapeResources = new ArrayList<>();
protected final List<LineShapeResource> mLineShapeResources = new ArrayList<>();
protected final List<SpriteSheetPngResource> mSpriteSheetPngResources = new ArrayList<>();
protected final List<TtfFontResource> mTtfFontResources = new ArrayList<>();
protected final List<StringResource> mStringResources = new ArrayList<>();
protected final List<OffloadString> mOffloadStrings = new ArrayList<>();
protected final List<StaticTextResource> mStaticTextResources = new ArrayList<>();
protected final List<DynamicTextResource> mDynamicTextResources = new ArrayList<>();
protected final List<OffloadRawMetric> mOffloadRawMetrics = new ArrayList<>();
protected final List<OffloadMetric> mOffloadMetrics = new ArrayList<>();
protected final List<OffloadConstant> mOffloadConstants = new ArrayList<>();
protected final List<LinearMetricMapping> mLinearMetricMappings = new ArrayList<>();
protected final List<RangeMapping> mRangeMappings = new ArrayList<>();
protected final List<ModuloMapping> mModuloMappings = new ArrayList<>();
protected final List<NumberFormatMapping> mNumberFormatMappings = new ArrayList<>();
protected final List<UnaryOperation> mUnaryOperations = new ArrayList<>();
protected final List<BinaryOperation> mBinaryOperations = new ArrayList<>();
protected final List<TernaryOperation> mTernaryOperations = new ArrayList<>();
private final int mCreatorPackageUid;
// LINT.ThenChange(:unpack_aidl_type_fields)
/**
* How many minutes this layout is valid for before we should wake up the device and send an
* onOffloadUpdate event to the application. Defaults to -1 for valid indefinitely.
*/
private int mMinutesValid = -1;
private boolean mShouldClearResource = true;
private boolean mIsOpen = false;
private boolean mIsWaitingDoze = false;
// Special case for brightness offload
private boolean mIsBrightnessOffload = false;
@VisibleForTesting
BaseOffloadLayout(int uid,
HalTypeConverterSupplier halTypeConverter,
HalResourceStore halResourceStore,
TextPreprocessor textPreprocessor
) {
mCreatorPackageUid = uid;
mHalTypeConverter = halTypeConverter;
mHalResourceStore = halResourceStore;
mTextPreprocessor = textPreprocessor;
}
void open() {
mIsOpen = true;
}
void close() {
mIsOpen = false;
}
boolean isOpen() {
return mIsOpen;
}
boolean isWaitingDoze() {
return mIsWaitingDoze;
}
int getUid() {
return mCreatorPackageUid;
}
int getMinutesValid() {
return mMinutesValid;
}
// LINT.IfChange(unpack_aidl_type_fields)
void updateFromBundle(Bundle bundle) {
// TODO(b/179528367): add functions and impls for partial replacement
bundle.setClassLoader(CustomResource.class.getClassLoader());
ArrayList<CustomResource> customResources = bundle.getParcelableArrayList(
FIELD_CUSTOM_RESOURCE);
if (customResources != null) {
mCustomResources.addAll(customResources);
}
mMinutesValid = bundle.getInt(FIELD_MINUTES_VALID, -1);
bundle.setClassLoader(TranslationGroup.class.getClassLoader());
ArrayList<TranslationGroup> translationGroups = bundle.getParcelableArrayList(
FIELD_TRANSLATION_GROUP);
if (translationGroups != null) {
// Special case for brightness offload
if (translationGroups.size() == 1 && translationGroups.get(0).id
== RESOURCE_ID_EMPTY_LAYOUT) {
mIsBrightnessOffload = true;
Log.i(TAG, "[BrightnessOffload] Enabled, layout uid=" + mCreatorPackageUid);
return;
}
mTranslationGroups.addAll(translationGroups);
}
bundle.setClassLoader(OffloadRawMetric.class.getClassLoader());
ArrayList<OffloadRawMetric> offloadRawMetrics
= bundle.getParcelableArrayList(FIELD_OFFLOAD_RAW_METRIC);
if (offloadRawMetrics != null) {
mOffloadRawMetrics.addAll(offloadRawMetrics);
}
bundle.setClassLoader(OffloadMetric.class.getClassLoader());
ArrayList<OffloadMetric> offloadMetrics = bundle.getParcelableArrayList(
FIELD_OFFLOAD_METRIC);
if (offloadMetrics != null) {
mOffloadMetrics.addAll(offloadMetrics);
}
bundle.setClassLoader(RotationGroup.class.getClassLoader());
ArrayList<RotationGroup> rotationGroups = bundle.getParcelableArrayList(
FIELD_ROTATION_GROUP);
if (rotationGroups != null) {
mRotationGroups.addAll(rotationGroups);
}
bundle.setClassLoader(BitmapResource.class.getClassLoader());
ArrayList<BitmapResource> bitmapResources =
bundle.getParcelableArrayList(FIELD_BITMAP_RESOURCE);
if (bitmapResources != null) {
mBitmapResources.addAll(bitmapResources);
}
bundle.setClassLoader(ArcPathResource.class.getClassLoader());
ArrayList<ArcPathResource> arcShapeResources = bundle.getParcelableArrayList(
FIELD_ARC_SHAPE_RESOURCE);
if (arcShapeResources != null) {
mArcPathResources.addAll(arcShapeResources);
}
bundle.setClassLoader(RectShapeResource.class.getClassLoader());
ArrayList<RectShapeResource> rectShapeResources = bundle.getParcelableArrayList(
FIELD_RECT_SHAPE_RESOURCE);
if (rectShapeResources != null) {
mRectShapeResources.addAll(rectShapeResources);
}
bundle.setClassLoader(RoundRectShapeResource.class.getClassLoader());
ArrayList<RoundRectShapeResource> roundRectShapeResources = bundle.getParcelableArrayList(
FIELD_ROUND_RECT_SHAPE_RESOURCE);
if (roundRectShapeResources != null) {
mRoundRectShapeResources.addAll(roundRectShapeResources);
}
bundle.setClassLoader(LineShapeResource.class.getClassLoader());
ArrayList<LineShapeResource> lineShapeResources = bundle.getParcelableArrayList(
FIELD_LINE_SHAPE_RESOURCE);
if (lineShapeResources != null) {
mLineShapeResources.addAll(lineShapeResources);
}
bundle.setClassLoader(SpriteSheetPngResource.class.getClassLoader());
ArrayList<SpriteSheetPngResource> spriteSheetPngResource = bundle.getParcelableArrayList(
FIELD_SPRITE_SHEET_PNG_RESOURCE);
if (spriteSheetPngResource != null) {
mSpriteSheetPngResources.addAll(spriteSheetPngResource);
}
bundle.setClassLoader(TtfFontResource.class.getClassLoader());
ArrayList<TtfFontResource> ttfFontResources = bundle.getParcelableArrayList(
FIELD_TTF_FONT_RESOURCE);
if (ttfFontResources != null) {
mTtfFontResources.addAll(ttfFontResources);
}
bundle.setClassLoader(StringResource.class.getClassLoader());
ArrayList<StringResource> stringResources = bundle.getParcelableArrayList(
FIELD_STRING_RESOURCE);
if (stringResources != null) {
mStringResources.addAll(stringResources);
}
bundle.setClassLoader(OffloadConstant.class.getClassLoader());
ArrayList<OffloadConstant> offloadConstants = bundle.getParcelableArrayList(
FIELD_OFFLOAD_CONSTANT);
if (offloadConstants != null) {
mOffloadConstants.addAll(offloadConstants);
}
bundle.setClassLoader(OffloadString.class.getClassLoader());
ArrayList<OffloadString> offloadStrings = bundle.getParcelableArrayList(
FIELD_OFFLOAD_STRING);
if (offloadStrings != null) {
mOffloadStrings.addAll(offloadStrings);
}
bundle.setClassLoader(StaticTextResource.class.getClassLoader());
ArrayList<StaticTextResource> staticTextResources = bundle.getParcelableArrayList(
FIELD_STATIC_TEXT);
if (staticTextResources != null) {
mStaticTextResources.addAll(staticTextResources);
}
bundle.setClassLoader(DynamicTextResource.class.getClassLoader());
ArrayList<DynamicTextResource> dynamicTextResources = bundle.getParcelableArrayList(
FIELD_DYNAMIC_TEXT);
if (dynamicTextResources != null) {
mDynamicTextResources.addAll(dynamicTextResources);
}
bundle.setClassLoader(LinearMetricMapping.class.getClassLoader());
ArrayList<LinearMetricMapping> linearMappings = bundle.getParcelableArrayList(
FIELD_MAPPING_LINEAR);
if (linearMappings != null) {
mLinearMetricMappings.addAll(linearMappings);
}
bundle.setClassLoader(RangeMapping.class.getClassLoader());
ArrayList<RangeMapping> rangeMappings = bundle.getParcelableArrayList(FIELD_MAPPING_RANGE);
if (rangeMappings != null) {
mRangeMappings.addAll(rangeMappings);
}
bundle.setClassLoader(ModuloMapping.class.getClassLoader());
ArrayList<ModuloMapping> moduloMappings = bundle.getParcelableArrayList(
FIELD_MAPPING_MODULO);
if (moduloMappings != null) {
mModuloMappings.addAll(moduloMappings);
}
bundle.setClassLoader(NumberFormatMapping.class.getClassLoader());
ArrayList<NumberFormatMapping> numberFormatMappings = bundle.getParcelableArrayList(
FIELD_MAPPING_NUMBER_FORMAT);
if (numberFormatMappings != null) {
mNumberFormatMappings.addAll(numberFormatMappings);
}
bundle.setClassLoader(UnaryOperation.class.getClassLoader());
ArrayList<UnaryOperation> unaryOperation = bundle.getParcelableArrayList(
FIELD_UNARY_OPERATION);
if (unaryOperation != null) {
mUnaryOperations.addAll(unaryOperation);
}
bundle.setClassLoader(BinaryOperation.class.getClassLoader());
ArrayList<BinaryOperation> binaryOperations = bundle.getParcelableArrayList(
FIELD_BINARY_OPERATION);
if (binaryOperations != null) {
mBinaryOperations.addAll(binaryOperations);
}
bundle.setClassLoader(TernaryOperation.class.getClassLoader());
ArrayList<TernaryOperation> ternaryOperations = bundle.getParcelableArrayList(
FIELD_TERNARY_OPERATION);
if (ternaryOperations != null) {
mTernaryOperations.addAll(ternaryOperations);
}
}
// LINT.ThenChange(OffloadLayout.java:buildHalResourceHelper)
void addStatusBar(TranslationGroup statusBarGroup, BitmapResource statusBarBitmap) {
if (mIsBrightnessOffload) {
Log.i(TAG, "[BrightnessOffload] Skipping status bar.");
return;
}
mTranslationGroups.add(statusBarGroup);
mBitmapResources.add(statusBarBitmap);
}
protected abstract void buildHalResourceHelper() throws DisplayOffloadException;
public void markWaitingDoze() {
mIsWaitingDoze = true;
}
public void markHalResourcesDirty() {
Log.i(TAG, "markHalResourcesDirty: uid=" + mCreatorPackageUid);
mHalResourceStore.markAllDirty();
mShouldClearResource = true;
mIsWaitingDoze = false;
}
/**
* Convert and validate HAL resource, generates a send order based on topological sort
*
* @throws DisplayOffloadException if conversion or validation fails
*/
public void validateHalResource() throws DisplayOffloadException {
if (mIsBrightnessOffload) {
// mHalResourceStore should only contain a single TranslationGroup in this case
Log.i(TAG, "[BrightnessOffload] Creating empty layout.");
mHalResourceStore.clear();
mHalTypeConverter.getConverter().begin();
mHalTypeConverter.getConverter().addEmptyTranslationGroup(mHalResourceStore);
mHalTypeConverter.getConverter().end();
} else {
try {
buildHalResourceHelper();
} catch (DisplayOffloadException e) {
Log.e(TAG, "buildHalResource: error while building hal resources", e);
throw e;
} finally {
// Clean up
mTextPreprocessor.cleanup();
}
}
mHalResourceStore.generateSendOrder();
}
/**
* Send dirty resources to HAL with lock to HAL held.
*
* @param halAdapter for abstracting HAL details
* @throws DisplayOffloadException if HAL call fails in anyways
*/
public void sendToHal(HalAdapter halAdapter) throws DisplayOffloadException {
if (mShouldClearResource) {
halAdapter.resetResource();
mHalResourceStore.markAllDirty();
}
mHalResourceStore.sendToHal(halAdapter);
mShouldClearResource = false;
mIsWaitingDoze = false;
}
/**
* Returns if the OffloadLayout contains any valid resources.
* Must be called after validateHalResource.
*
* @return true if the OffloadLayout contains at least one valid resource
*/
public boolean isEmpty() {
return mHalResourceStore.isEmpty();
}
/**
* Compute the root resource of this OffloadLayout
*
* @return id of the HAL resource that's the root
* @throws DisplayOffloadException if there are no root
*/
public int getRootId() throws DisplayOffloadException {
return mHalResourceStore.getRootId();
}
boolean isBrightnessOffload() {
return mIsBrightnessOffload;
}
void dump(IndentingPrintWriter ipw) {
ipw.printPair("mIsOpen", mIsOpen);
ipw.printPair("mCreatorPackageUid", mCreatorPackageUid);
ipw.printPair("mIsBrightnessOffload", mIsBrightnessOffload);
ipw.println();
ipw.println("mHalResourceStore");
ipw.increaseIndent();
mHalResourceStore.dump(ipw);
ipw.decreaseIndent();
}
}