Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2af98404 authored by Willie Koomson's avatar Willie Koomson
Browse files

Write RemoteViews actions to proto (1/3)

This change adds support for writing the following RemoteViews actions to
proto:
  AttributeReflectionAction
  BitmapReflectionAction
  ComplexUnitDimensionReflectionAction
  LayoutParamAction
  NightModeReflectionAction
  ReflectionAction
  RemoveFromParentAction

Test: RemoteViewsProto test
Bug: 308041327
Flag: android.appwidget.flags.remote_views_proto
Change-Id: I3b191abdb518123c3f5d2c0ed5be1672c4fd21cd
parent cd8db6b6
Loading
Loading
Loading
Loading
+869 −4

File changed.

Preview size limit exceeded, changes collapsed.

+86 −0
Original line number Diff line number Diff line
@@ -54,6 +54,7 @@ message RemoteViewsProto {
    optional bool has_draw_instructions = 13;
    repeated bytes bitmap_cache = 14;
    optional RemoteCollectionCache remote_collection_cache = 15;
    repeated Action actions = 16;

    message RemoteCollectionCache {
        message Entry {
@@ -288,6 +289,91 @@ message RemoteViewsProto {
            }
        }
    }

    message Action {
        oneof action {
            AttributeReflectionAction attribute_reflection_action = 1;
            BitmapReflectionAction bitmap_reflection_action = 2;
            ComplexUnitDimensionReflectionAction complex_unit_dimension_reflection_action = 3;
            LayoutParamAction layout_param_action = 4;
            NightModeReflectionAction night_mode_reflection_action = 5;
            ReflectionAction reflection_action = 6;
            RemoveFromParentAction remove_from_parent_action = 7;
        }
    }

    message AttributeReflectionAction {
        optional string view_id = 1;
        optional string method_name = 2;
        optional int32 parameter_type = 3;
        optional int32 resource_type = 4;
        optional string attribute_id = 5;
    }

    message BitmapReflectionAction {
        optional string view_id = 1;
        optional string method_name = 2;
        optional int32 bitmap_id = 3;
    }

    message ComplexUnitDimensionReflectionAction {
        optional string view_id = 1;
        optional string method_name = 2;
        optional int32 parameter_type = 3;
        optional float dimension_value = 4;
        optional int32 unit = 5;
    }

    message LayoutParamAction {
        optional string view_id = 1;
        optional int32 property = 2;
        optional int32 layout_value = 3;
        optional int32 value_type = 4;
    }

    message NightModeReflectionAction {
        optional string view_id = 1;
        optional string method_name = 2;
        optional int32 parameter_type = 3;
        oneof light {
            Icon light_icon = 4;
            android.content.res.ColorStateListProto light_color_state_list = 5;
            int32 light_int = 6;
        }
        oneof dark {
            Icon dark_icon = 7;
            android.content.res.ColorStateListProto dark_color_state_list = 8;
            int32 dark_int = 9;
        }
    }

    message ReflectionAction {
        optional string view_id = 1;
        optional string method_name = 2;
        optional int32 parameter_type = 3;
        oneof reflection_value {
            bool boolean_value = 4;
            bytes byte_value = 5;
            int32 short_value = 6;
            int32 int_value = 7;
            int64 long_value = 8;
            float float_value = 9;
            double double_value = 10;
            int32 char_value = 11;
            string string_value = 12;
            CharSequence char_sequence_value = 13;
            string uri_value = 14;
            bytes bitmap_value = 15;
            android.content.res.ColorStateListProto color_state_list_value = 16;
            Icon icon_value = 17;
            int32 blend_mode_value = 18;
            // Intent and Bundle values are excluded.
        }
    }

    message RemoveFromParentAction {
        optional string view_id = 1;
    }
}


+0 −155
Original line number Diff line number Diff line
/*
 * 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 android.widget;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

import android.content.Context;
import android.util.SizeF;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;
import android.view.View;

import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;

import com.android.frameworks.coretests.R;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;

import java.util.Map;

/**
 * Tests for RemoteViews.
 */
@RunWith(AndroidJUnit4.class)
@SmallTest
public class RemoteViewsProtoTest {

    // This can point to any other package which exists on the device.
    private static final String OTHER_PACKAGE = "com.android.systemui";

    @Rule
    public final ExpectedException exception = ExpectedException.none();

    private Context mContext;
    private String mPackage;
    private LinearLayout mContainer;

    @Before
    public void setup() {
        mContext = InstrumentationRegistry.getContext();
        mPackage = mContext.getPackageName();
        mContainer = new LinearLayout(mContext);
    }

    @Test
    public void copy_canStillBeApplied() {
        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);

        RemoteViews clone = recreateFromProto(original);

        clone.apply(mContext, mContainer);
    }

    @SuppressWarnings("ReturnValueIgnored")
    @Test
    public void clone_repeatedly() {
        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);

        recreateFromProto(original);
        recreateFromProto(original);

        original.apply(mContext, mContainer);
    }

    @Test
    public void clone_chained() {
        RemoteViews original = new RemoteViews(mPackage, R.layout.remote_views_test);

        RemoteViews clone = recreateFromProto(recreateFromProto(original));


        clone.apply(mContext, mContainer);
    }

    @Test
    public void landscapePortraitViews_lightBackgroundLayoutFlag() {
        RemoteViews inner = new RemoteViews(mPackage, R.layout.remote_views_text);
        inner.setLightBackgroundLayoutId(R.layout.remote_views_light_background_text);

        RemoteViews parent = new RemoteViews(inner, inner);
        parent.addFlags(RemoteViews.FLAG_USE_LIGHT_BACKGROUND_LAYOUT);

        View view = recreateFromProto(parent).apply(mContext, mContainer);
        assertNull(view.findViewById(R.id.text));
        assertNotNull(view.findViewById(R.id.light_background_text));
    }

    @Test
    public void sizedViews_lightBackgroundLayoutFlag() {
        RemoteViews inner = new RemoteViews(mPackage, R.layout.remote_views_text);
        inner.setLightBackgroundLayoutId(R.layout.remote_views_light_background_text);

        RemoteViews parent = new RemoteViews(
                Map.of(new SizeF(0, 0), inner, new SizeF(100, 100), inner));
        parent.addFlags(RemoteViews.FLAG_USE_LIGHT_BACKGROUND_LAYOUT);

        View view = recreateFromProto(parent).apply(mContext, mContainer);
        assertNull(view.findViewById(R.id.text));
        assertNotNull(view.findViewById(R.id.light_background_text));
    }

    @Test
    public void nestedLandscapeViews() throws Exception {
        RemoteViews views = new RemoteViews(mPackage, R.layout.remote_views_test);
        for (int i = 0; i < 10; i++) {
            views = new RemoteViews(views, new RemoteViews(mPackage, R.layout.remote_views_test));
        }
        // writeTo/createFromProto works
        recreateFromProto(views);

        views = new RemoteViews(mPackage, R.layout.remote_views_test);
        for (int i = 0; i < 11; i++) {
            views = new RemoteViews(views, new RemoteViews(mPackage, R.layout.remote_views_test));
        }
        // writeTo/createFromProto fails
        exception.expect(IllegalArgumentException.class);
        recreateFromProtoNoRethrow(views);
    }

    private RemoteViews recreateFromProto(RemoteViews views) {
        try {
            return recreateFromProtoNoRethrow(views);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private RemoteViews recreateFromProtoNoRethrow(RemoteViews views) throws Exception {
        ProtoOutputStream out = new ProtoOutputStream();
        views.writePreviewToProto(mContext, out);
        ProtoInputStream in = new ProtoInputStream(out.getBytes());
        return RemoteViews.createPreviewFromProto(mContext, in);
    }
}