Loading core/java/android/app/assist/AssistStructure.java +2 −2 Original line number Diff line number Diff line Loading @@ -2173,7 +2173,7 @@ public class AssistStructure implements Parcelable { + ", hints=" + Arrays.toString(node.getAutofillHints()) + ", value=" + node.getAutofillValue() + ", sanitized=" + node.isSanitized() + ", importantFor=" + node.getImportantForAutofill()); + ", important=" + node.getImportantForAutofill()); } final int NCHILDREN = node.getChildCount(); Loading core/tests/coretests/AndroidManifest.xml +8 −0 Original line number Diff line number Diff line Loading @@ -1401,6 +1401,14 @@ <service android:name="android.content.CrossUserContentService" android:exported="true" /> <activity android:name="android.app.assist.EmptyLayoutActivity" android:label="My Title"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" /> </intent-filter> </activity> </application> <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" Loading core/tests/coretests/res/layout/empty_layout.xml 0 → 100644 +26 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- * Copyright (C) 2018 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. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/parent" android:layout_width="match_parent" android:layout_height="wrap_content" android:focusable="true" android:focusableInTouchMode="true" android:orientation="vertical"> </LinearLayout> core/tests/coretests/src/android/app/assist/AssistStructureTest.java 0 → 100644 +269 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.app.assist; import static android.view.View.IMPORTANT_FOR_AUTOFILL_AUTO; import static com.google.common.truth.Truth.assertThat; import android.app.assist.AssistStructure.ViewNode; import android.content.ComponentName; import android.content.Context; import android.os.Parcel; import android.os.SystemClock; import android.support.test.InstrumentationRegistry; import android.support.test.rule.ActivityTestRule; import android.support.test.runner.AndroidJUnit4; import android.util.Log; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; /** * Unit test for {@link AssistStructure}. * * <p>To run it: {@code atest app.assist.AssistStructureTest} * * <p>TODO: right now this test is focused in the parcelization of a big object, due to an * upcoming refactoring on the Autofill parcelization that does not use * {@link AssistStructure#ensureData()} to load the structure (which in turn requires calls from * system server to the app). Ideally it should be emprove to: * * <ol> * <li>Add tests for Assist (to make sure autofill properties are not parcelized). * <li>Assert all properties and make sure just the relevant properties (for Autofill or Assist) * are parcelized. * <li>Add tests for Autofill requests with the {@code FLAG_MANUAL_REQUEST} flag. * </ol> */ @RunWith(AndroidJUnit4.class) public class AssistStructureTest { private static final String TAG = "AssistStructureTest"; private static final boolean FOR_AUTOFILL = true; private static final int NO_FLAGS = 0; private static final int BIG_VIEW_SIZE = 10_000_000; private static final char BIG_VIEW_CHAR = '6'; private static final String BIG_STRING = repeat(BIG_VIEW_CHAR, BIG_VIEW_SIZE); // Cannot be much big because it could hang test due to blocking GC private static final int NUMBER_SMALL_VIEWS = 10_000; private EmptyLayoutActivity mActivity; private final ActivityTestRule<EmptyLayoutActivity> mActivityTestRule = new ActivityTestRule<>(EmptyLayoutActivity.class); private final Context mContext = InstrumentationRegistry.getTargetContext(); @Before public void setup() { mActivity = mActivityTestRule.launchActivity(null); } @Test public void testParcelizationForAutofill_manySmallViews() { Log.d(TAG, "Adding " + NUMBER_SMALL_VIEWS + " small views"); for (int i = 1; i <= NUMBER_SMALL_VIEWS; i++) { mActivity.addView(newSmallView()); } waitUntilViewsAreLaidOff(); AssistStructure structure = new AssistStructure(mActivity, FOR_AUTOFILL, NO_FLAGS); // Check properties on "original" structure assertStructureWithManySmallViews(structure); // Check properties on "cloned" structure AssistStructure clone = cloneThroughParcel(structure); assertStructureWithManySmallViews(clone); } private void assertStructureWithManySmallViews(AssistStructure structure) { int i = 0; try { assertPackageName(structure); assertThat(structure.getWindowNodeCount()).isEqualTo(1); ViewNode rootView = structure.getWindowNodeAt(0).getRootViewNode(); assertThat(rootView.getClassName()).isEqualTo(FrameLayout.class.getName()); assertThat(rootView.getChildCount()).isEqualTo(2); // title and parent assertThat(rootView.getAutofillId()).isNotNull(); assertThat(rootView.getImportantForAutofill()).isEqualTo(IMPORTANT_FOR_AUTOFILL_AUTO); // Title ViewNode title = rootView.getChildAt(0); assertThat(title.getClassName()).isEqualTo(TextView.class.getName()); assertThat(title.getChildCount()).isEqualTo(0); assertThat(title.getText().toString()).isEqualTo("My Title"); assertThat(title.getAutofillId()).isNotNull(); // Parent ViewNode parent = rootView.getChildAt(1); assertThat(parent.getClassName()).isEqualTo(LinearLayout.class.getName()); assertThat(parent.getChildCount()).isEqualTo(NUMBER_SMALL_VIEWS); assertThat(parent.getIdEntry()).isEqualTo("parent"); assertThat(parent.getAutofillId()).isNotNull(); // Children for (i = 0; i < NUMBER_SMALL_VIEWS; i++) { ViewNode smallView = parent.getChildAt(i); assertSmallView(smallView); } } catch (RuntimeException | Error e) { Log.e(TAG, "dumping structure because of error at index #" + i + ": " + e); structure.dump(true); throw e; } } @Test public void testParcelizationForAutofill_oneBigView() { Log.d(TAG, "Adding view with " + BIG_VIEW_SIZE + " chars"); mActivity.addView(newBigView()); waitUntilViewsAreLaidOff(); AssistStructure structure = new AssistStructure(mActivity, FOR_AUTOFILL, NO_FLAGS); // Check properties on "original" structure assertStructureWithOneBigView(structure); // Check properties on "cloned" structure AssistStructure clone = cloneThroughParcel(structure); assertStructureWithOneBigView(clone); } private void assertStructureWithOneBigView(AssistStructure structure) { try { assertPackageName(structure); assertThat(structure.getWindowNodeCount()).isEqualTo(1); ViewNode rootView = structure.getWindowNodeAt(0).getRootViewNode(); assertThat(rootView.getClassName()).isEqualTo(FrameLayout.class.getName()); assertThat(rootView.getChildCount()).isEqualTo(2); // title and parent assertThat(rootView.getAutofillId()).isNotNull(); assertThat(rootView.getImportantForAutofill()).isEqualTo(IMPORTANT_FOR_AUTOFILL_AUTO); // Title ViewNode title = rootView.getChildAt(0); assertThat(title.getClassName()).isEqualTo(TextView.class.getName()); assertThat(title.getChildCount()).isEqualTo(0); assertThat(title.getText().toString()).isEqualTo("My Title"); assertThat(title.getAutofillId()).isNotNull(); // Parent ViewNode parent = rootView.getChildAt(1); assertThat(parent.getClassName()).isEqualTo(LinearLayout.class.getName()); assertThat(parent.getChildCount()).isEqualTo(1); assertThat(parent.getIdEntry()).isEqualTo("parent"); assertThat(parent.getAutofillId()).isNotNull(); // Children ViewNode bigView = parent.getChildAt(0); assertBigView(bigView); } catch (RuntimeException | Error e) { Log.e(TAG, "dumping structure because of error: " + e); structure.dump(true); throw e; } } private EditText newSmallView() { EditText view = new EditText(mContext); view.setText("I AM GROOT"); return view; } private void assertSmallView(ViewNode view) { assertThat(view.getClassName()).isEqualTo(EditText.class.getName()); assertThat(view.getChildCount()).isEqualTo(0); assertThat(view.getIdEntry()).isNull(); assertThat(view.getAutofillId()).isNotNull(); assertThat(view.getText().toString()).isEqualTo("I AM GROOT"); } private EditText newBigView() { EditText view = new EditText(mContext); view.setText("Big Hint in Little View"); view.setAutofillHints(BIG_STRING); return view; } private void assertBigView(ViewNode view) { assertThat(view.getClassName()).isEqualTo(EditText.class.getName()); assertThat(view.getChildCount()).isEqualTo(0); assertThat(view.getIdEntry()).isNull(); assertThat(view.getAutofillId()).isNotNull(); assertThat(view.getText().toString()).isEqualTo("Big Hint in Little View"); String[] hints = view.getAutofillHints(); assertThat(hints.length).isEqualTo(1); String hint = hints[0]; // Cannot assert the whole string because it takes too long and crashes the test by ANR assertThat(hint.length()).isEqualTo(BIG_VIEW_SIZE); assertThat(hint.charAt(0)).isEqualTo(BIG_VIEW_CHAR); assertThat(hint.charAt(BIG_VIEW_SIZE - 1)).isEqualTo(BIG_VIEW_CHAR); } private void assertPackageName(AssistStructure structure) { assertThat(structure.getActivityComponent()).isEqualTo( new ComponentName("com.android.frameworks.coretests", "android.app.assist.EmptyLayoutActivity")); } private AssistStructure cloneThroughParcel(AssistStructure structure) { Parcel parcel = Parcel.obtain(); try { // Write to parcel parcel.setDataPosition(0); // Sanity / paranoid check structure.writeToParcel(parcel, NO_FLAGS); // Read from parcel parcel.setDataPosition(0); AssistStructure clone = AssistStructure.CREATOR.createFromParcel(parcel); assertThat(clone).isNotNull(); return clone; } finally { parcel.recycle(); } } private void waitUntilViewsAreLaidOff() { // TODO: use a more robust mechanism than just sleeping SystemClock.sleep(3000); } // TODO: use some common helper private static String repeat(char c, int size) { StringBuilder builder = new StringBuilder(size); for (int i = 1; i <= size; i++) { builder.append(c); } return builder.toString(); } } core/tests/coretests/src/android/app/assist/EmptyLayoutActivity.java 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.app.assist; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.WindowManager.LayoutParams; import android.widget.LinearLayout; import com.android.frameworks.coretests.R; public class EmptyLayoutActivity extends Activity { private LinearLayout mParent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.empty_layout); mParent = findViewById(R.id.parent); } public void addView(View view) { view.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); runOnUiThread(() -> mParent.addView(view)); } } Loading
core/java/android/app/assist/AssistStructure.java +2 −2 Original line number Diff line number Diff line Loading @@ -2173,7 +2173,7 @@ public class AssistStructure implements Parcelable { + ", hints=" + Arrays.toString(node.getAutofillHints()) + ", value=" + node.getAutofillValue() + ", sanitized=" + node.isSanitized() + ", importantFor=" + node.getImportantForAutofill()); + ", important=" + node.getImportantForAutofill()); } final int NCHILDREN = node.getChildCount(); Loading
core/tests/coretests/AndroidManifest.xml +8 −0 Original line number Diff line number Diff line Loading @@ -1401,6 +1401,14 @@ <service android:name="android.content.CrossUserContentService" android:exported="true" /> <activity android:name="android.app.assist.EmptyLayoutActivity" android:label="My Title"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" /> </intent-filter> </activity> </application> <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" Loading
core/tests/coretests/res/layout/empty_layout.xml 0 → 100644 +26 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- * Copyright (C) 2018 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. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/parent" android:layout_width="match_parent" android:layout_height="wrap_content" android:focusable="true" android:focusableInTouchMode="true" android:orientation="vertical"> </LinearLayout>
core/tests/coretests/src/android/app/assist/AssistStructureTest.java 0 → 100644 +269 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.app.assist; import static android.view.View.IMPORTANT_FOR_AUTOFILL_AUTO; import static com.google.common.truth.Truth.assertThat; import android.app.assist.AssistStructure.ViewNode; import android.content.ComponentName; import android.content.Context; import android.os.Parcel; import android.os.SystemClock; import android.support.test.InstrumentationRegistry; import android.support.test.rule.ActivityTestRule; import android.support.test.runner.AndroidJUnit4; import android.util.Log; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.LinearLayout; import android.widget.TextView; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; /** * Unit test for {@link AssistStructure}. * * <p>To run it: {@code atest app.assist.AssistStructureTest} * * <p>TODO: right now this test is focused in the parcelization of a big object, due to an * upcoming refactoring on the Autofill parcelization that does not use * {@link AssistStructure#ensureData()} to load the structure (which in turn requires calls from * system server to the app). Ideally it should be emprove to: * * <ol> * <li>Add tests for Assist (to make sure autofill properties are not parcelized). * <li>Assert all properties and make sure just the relevant properties (for Autofill or Assist) * are parcelized. * <li>Add tests for Autofill requests with the {@code FLAG_MANUAL_REQUEST} flag. * </ol> */ @RunWith(AndroidJUnit4.class) public class AssistStructureTest { private static final String TAG = "AssistStructureTest"; private static final boolean FOR_AUTOFILL = true; private static final int NO_FLAGS = 0; private static final int BIG_VIEW_SIZE = 10_000_000; private static final char BIG_VIEW_CHAR = '6'; private static final String BIG_STRING = repeat(BIG_VIEW_CHAR, BIG_VIEW_SIZE); // Cannot be much big because it could hang test due to blocking GC private static final int NUMBER_SMALL_VIEWS = 10_000; private EmptyLayoutActivity mActivity; private final ActivityTestRule<EmptyLayoutActivity> mActivityTestRule = new ActivityTestRule<>(EmptyLayoutActivity.class); private final Context mContext = InstrumentationRegistry.getTargetContext(); @Before public void setup() { mActivity = mActivityTestRule.launchActivity(null); } @Test public void testParcelizationForAutofill_manySmallViews() { Log.d(TAG, "Adding " + NUMBER_SMALL_VIEWS + " small views"); for (int i = 1; i <= NUMBER_SMALL_VIEWS; i++) { mActivity.addView(newSmallView()); } waitUntilViewsAreLaidOff(); AssistStructure structure = new AssistStructure(mActivity, FOR_AUTOFILL, NO_FLAGS); // Check properties on "original" structure assertStructureWithManySmallViews(structure); // Check properties on "cloned" structure AssistStructure clone = cloneThroughParcel(structure); assertStructureWithManySmallViews(clone); } private void assertStructureWithManySmallViews(AssistStructure structure) { int i = 0; try { assertPackageName(structure); assertThat(structure.getWindowNodeCount()).isEqualTo(1); ViewNode rootView = structure.getWindowNodeAt(0).getRootViewNode(); assertThat(rootView.getClassName()).isEqualTo(FrameLayout.class.getName()); assertThat(rootView.getChildCount()).isEqualTo(2); // title and parent assertThat(rootView.getAutofillId()).isNotNull(); assertThat(rootView.getImportantForAutofill()).isEqualTo(IMPORTANT_FOR_AUTOFILL_AUTO); // Title ViewNode title = rootView.getChildAt(0); assertThat(title.getClassName()).isEqualTo(TextView.class.getName()); assertThat(title.getChildCount()).isEqualTo(0); assertThat(title.getText().toString()).isEqualTo("My Title"); assertThat(title.getAutofillId()).isNotNull(); // Parent ViewNode parent = rootView.getChildAt(1); assertThat(parent.getClassName()).isEqualTo(LinearLayout.class.getName()); assertThat(parent.getChildCount()).isEqualTo(NUMBER_SMALL_VIEWS); assertThat(parent.getIdEntry()).isEqualTo("parent"); assertThat(parent.getAutofillId()).isNotNull(); // Children for (i = 0; i < NUMBER_SMALL_VIEWS; i++) { ViewNode smallView = parent.getChildAt(i); assertSmallView(smallView); } } catch (RuntimeException | Error e) { Log.e(TAG, "dumping structure because of error at index #" + i + ": " + e); structure.dump(true); throw e; } } @Test public void testParcelizationForAutofill_oneBigView() { Log.d(TAG, "Adding view with " + BIG_VIEW_SIZE + " chars"); mActivity.addView(newBigView()); waitUntilViewsAreLaidOff(); AssistStructure structure = new AssistStructure(mActivity, FOR_AUTOFILL, NO_FLAGS); // Check properties on "original" structure assertStructureWithOneBigView(structure); // Check properties on "cloned" structure AssistStructure clone = cloneThroughParcel(structure); assertStructureWithOneBigView(clone); } private void assertStructureWithOneBigView(AssistStructure structure) { try { assertPackageName(structure); assertThat(structure.getWindowNodeCount()).isEqualTo(1); ViewNode rootView = structure.getWindowNodeAt(0).getRootViewNode(); assertThat(rootView.getClassName()).isEqualTo(FrameLayout.class.getName()); assertThat(rootView.getChildCount()).isEqualTo(2); // title and parent assertThat(rootView.getAutofillId()).isNotNull(); assertThat(rootView.getImportantForAutofill()).isEqualTo(IMPORTANT_FOR_AUTOFILL_AUTO); // Title ViewNode title = rootView.getChildAt(0); assertThat(title.getClassName()).isEqualTo(TextView.class.getName()); assertThat(title.getChildCount()).isEqualTo(0); assertThat(title.getText().toString()).isEqualTo("My Title"); assertThat(title.getAutofillId()).isNotNull(); // Parent ViewNode parent = rootView.getChildAt(1); assertThat(parent.getClassName()).isEqualTo(LinearLayout.class.getName()); assertThat(parent.getChildCount()).isEqualTo(1); assertThat(parent.getIdEntry()).isEqualTo("parent"); assertThat(parent.getAutofillId()).isNotNull(); // Children ViewNode bigView = parent.getChildAt(0); assertBigView(bigView); } catch (RuntimeException | Error e) { Log.e(TAG, "dumping structure because of error: " + e); structure.dump(true); throw e; } } private EditText newSmallView() { EditText view = new EditText(mContext); view.setText("I AM GROOT"); return view; } private void assertSmallView(ViewNode view) { assertThat(view.getClassName()).isEqualTo(EditText.class.getName()); assertThat(view.getChildCount()).isEqualTo(0); assertThat(view.getIdEntry()).isNull(); assertThat(view.getAutofillId()).isNotNull(); assertThat(view.getText().toString()).isEqualTo("I AM GROOT"); } private EditText newBigView() { EditText view = new EditText(mContext); view.setText("Big Hint in Little View"); view.setAutofillHints(BIG_STRING); return view; } private void assertBigView(ViewNode view) { assertThat(view.getClassName()).isEqualTo(EditText.class.getName()); assertThat(view.getChildCount()).isEqualTo(0); assertThat(view.getIdEntry()).isNull(); assertThat(view.getAutofillId()).isNotNull(); assertThat(view.getText().toString()).isEqualTo("Big Hint in Little View"); String[] hints = view.getAutofillHints(); assertThat(hints.length).isEqualTo(1); String hint = hints[0]; // Cannot assert the whole string because it takes too long and crashes the test by ANR assertThat(hint.length()).isEqualTo(BIG_VIEW_SIZE); assertThat(hint.charAt(0)).isEqualTo(BIG_VIEW_CHAR); assertThat(hint.charAt(BIG_VIEW_SIZE - 1)).isEqualTo(BIG_VIEW_CHAR); } private void assertPackageName(AssistStructure structure) { assertThat(structure.getActivityComponent()).isEqualTo( new ComponentName("com.android.frameworks.coretests", "android.app.assist.EmptyLayoutActivity")); } private AssistStructure cloneThroughParcel(AssistStructure structure) { Parcel parcel = Parcel.obtain(); try { // Write to parcel parcel.setDataPosition(0); // Sanity / paranoid check structure.writeToParcel(parcel, NO_FLAGS); // Read from parcel parcel.setDataPosition(0); AssistStructure clone = AssistStructure.CREATOR.createFromParcel(parcel); assertThat(clone).isNotNull(); return clone; } finally { parcel.recycle(); } } private void waitUntilViewsAreLaidOff() { // TODO: use a more robust mechanism than just sleeping SystemClock.sleep(3000); } // TODO: use some common helper private static String repeat(char c, int size) { StringBuilder builder = new StringBuilder(size); for (int i = 1; i <= size; i++) { builder.append(c); } return builder.toString(); } }
core/tests/coretests/src/android/app/assist/EmptyLayoutActivity.java 0 → 100644 +44 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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.app.assist; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.WindowManager.LayoutParams; import android.widget.LinearLayout; import com.android.frameworks.coretests.R; public class EmptyLayoutActivity extends Activity { private LinearLayout mParent; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.empty_layout); mParent = findViewById(R.id.parent); } public void addView(View view) { view.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); runOnUiThread(() -> mParent.addView(view)); } }