Add manual rollback sample app
This application can be installed as a signature app. It displays
all available rollbacks, and will manually trigger the rollback of
all selected rollback IDs. This application will not trigger a
reboot in the case of staged rollbacks.
Test: m SampleRollbackApp, adb install. Manually install a train
with rollback enabled and reboot. Verify that the available
rollback is displayed, and that the rollback can be committed.
Bug: 220204580
Change-Id: Id2e5afac9e25532d8c24ea2b803c07dcfdb84d85
This commit is contained in:
32
tests/RollbackTest/SampleRollbackApp/Android.bp
Normal file
32
tests/RollbackTest/SampleRollbackApp/Android.bp
Normal file
@@ -0,0 +1,32 @@
|
||||
// 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 {
|
||||
// See: http://go/android-license-faq
|
||||
// A large-scale-change added 'default_applicable_licenses' to import
|
||||
// all of the 'license_kinds' from "frameworks_base_license"
|
||||
// to get the below license kinds:
|
||||
// SPDX-license-identifier-Apache-2.0
|
||||
default_applicable_licenses: ["frameworks_base_license"],
|
||||
}
|
||||
|
||||
android_app {
|
||||
name: "SampleRollbackApp",
|
||||
srcs: [
|
||||
"src/**/*.java",
|
||||
],
|
||||
resource_dirs: ["res"],
|
||||
certificate: "platform",
|
||||
sdk_version: "system_current",
|
||||
}
|
||||
31
tests/RollbackTest/SampleRollbackApp/AndroidManifest.xml
Normal file
31
tests/RollbackTest/SampleRollbackApp/AndroidManifest.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.sample.rollbackapp" >
|
||||
<uses-permission android:name="android.permission.TEST_MANAGE_ROLLBACKS" />
|
||||
<application
|
||||
android:label="@string/title_activity_main">
|
||||
<activity
|
||||
android:name="com.android.sample.rollbackapp.MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<Button
|
||||
android:id="@+id/trigger_rollback_button"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:text="Rollback Selected" />
|
||||
|
||||
<ListView
|
||||
android:id="@+id/listView"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:divider="?android:attr/dividerHorizontal"
|
||||
android:dividerHeight="1dp" />
|
||||
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp">
|
||||
<TextView android:id="@+id/rollback_id"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="20dp"/>
|
||||
<TextView android:id="@+id/rollback_packages"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="16dp"/>
|
||||
<CheckBox android:id="@+id/checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Roll Back"/>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
20
tests/RollbackTest/SampleRollbackApp/res/values/strings.xml
Normal file
20
tests/RollbackTest/SampleRollbackApp/res/values/strings.xml
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="title_activity_main" description="Launcher title">Rollback Sample App</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* 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.sample.rollbackapp;
|
||||
|
||||
import static android.app.PendingIntent.FLAG_MUTABLE;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.rollback.PackageRollbackInfo;
|
||||
import android.content.rollback.RollbackInfo;
|
||||
import android.content.rollback.RollbackManager;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class MainActivity extends Activity {
|
||||
|
||||
List<Integer> mIdsToRollback = new ArrayList<>();
|
||||
Button mTriggerRollbackButton;
|
||||
RollbackManager mRollbackManager;
|
||||
static final String ROLLBACK_ID_EXTRA = "rollbackId";
|
||||
static final String ACTION_NAME = MainActivity.class.getName();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
ListView rollbackListView = findViewById(R.id.listView);
|
||||
mRollbackManager = getApplicationContext().getSystemService(RollbackManager.class);
|
||||
initTriggerRollbackButton();
|
||||
|
||||
// Populate list of available rollbacks.
|
||||
List<RollbackInfo> availableRollbacks = mRollbackManager.getAvailableRollbacks();
|
||||
CustomAdapter adapter = new CustomAdapter(availableRollbacks);
|
||||
rollbackListView.setAdapter(adapter);
|
||||
|
||||
// Register receiver for rollback status events.
|
||||
getApplicationContext().registerReceiver(
|
||||
new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context,
|
||||
Intent intent) {
|
||||
int rollbackId = intent.getIntExtra(ROLLBACK_ID_EXTRA, -1);
|
||||
int rollbackStatusCode = intent.getIntExtra(RollbackManager.EXTRA_STATUS,
|
||||
RollbackManager.STATUS_FAILURE);
|
||||
String rollbackStatus = "FAILED";
|
||||
if (rollbackStatusCode == RollbackManager.STATUS_SUCCESS) {
|
||||
rollbackStatus = "SUCCESS";
|
||||
}
|
||||
makeToast("Status for rollback ID " + rollbackId + " is " + rollbackStatus);
|
||||
}}, new IntentFilter(ACTION_NAME), Context.RECEIVER_NOT_EXPORTED);
|
||||
}
|
||||
|
||||
private void initTriggerRollbackButton() {
|
||||
mTriggerRollbackButton = findViewById(R.id.trigger_rollback_button);
|
||||
mTriggerRollbackButton.setClickable(false);
|
||||
mTriggerRollbackButton.setOnClickListener(v -> {
|
||||
// Commits all selected rollbacks. Rollback status events will be sent to our receiver.
|
||||
for (int i = 0; i < mIdsToRollback.size(); i++) {
|
||||
Intent intent = new Intent(ACTION_NAME);
|
||||
intent.putExtra(ROLLBACK_ID_EXTRA, mIdsToRollback.get(i));
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(
|
||||
getApplicationContext(), 0, intent, FLAG_MUTABLE);
|
||||
mRollbackManager.commitRollback(mIdsToRollback.get(i),
|
||||
Collections.emptyList(),
|
||||
pendingIntent.getIntentSender());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void makeToast(String message) {
|
||||
runOnUiThread(() -> Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show());
|
||||
}
|
||||
|
||||
public class CustomAdapter extends BaseAdapter {
|
||||
List<RollbackInfo> mRollbackInfos;
|
||||
LayoutInflater mInflater = LayoutInflater.from(getApplicationContext());
|
||||
|
||||
CustomAdapter(List<RollbackInfo> rollbackInfos) {
|
||||
mRollbackInfos = rollbackInfos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mRollbackInfos.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return mRollbackInfos.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return mRollbackInfos.get(position).getRollbackId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View view, ViewGroup parent) {
|
||||
if (view == null) {
|
||||
view = mInflater.inflate(R.layout.listitem_rollbackinfo, null);
|
||||
}
|
||||
RollbackInfo rollbackInfo = mRollbackInfos.get(position);
|
||||
TextView rollbackIdView = view.findViewById(R.id.rollback_id);
|
||||
rollbackIdView.setText("Rollback ID " + rollbackInfo.getRollbackId());
|
||||
TextView rollbackPackagesTextView = view.findViewById(R.id.rollback_packages);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < rollbackInfo.getPackages().size(); i++) {
|
||||
PackageRollbackInfo pkgInfo = rollbackInfo.getPackages().get(i);
|
||||
sb.append(pkgInfo.getPackageName() + ": "
|
||||
+ pkgInfo.getVersionRolledBackFrom().getLongVersionCode() + " -> "
|
||||
+ pkgInfo.getVersionRolledBackTo().getLongVersionCode() + ",");
|
||||
}
|
||||
sb.deleteCharAt(sb.length() - 1);
|
||||
rollbackPackagesTextView.setText(sb.toString());
|
||||
CheckBox checkbox = view.findViewById(R.id.checkbox);
|
||||
checkbox.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
if (isChecked) {
|
||||
mIdsToRollback.add(rollbackInfo.getRollbackId());
|
||||
} else {
|
||||
mIdsToRollback.remove(Integer.valueOf(rollbackInfo.getRollbackId()));
|
||||
}
|
||||
mTriggerRollbackButton.setClickable(mIdsToRollback.size() > 0);
|
||||
});
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user