New API demo for installing/uninstalling applications.

Change-Id: Idaaf2003a6a34f2859887be32c82416ba4d06852
This commit is contained in:
Dianne Hackborn
2011-08-09 19:36:44 -07:00
parent a583cd15f7
commit ddea282ae9
6 changed files with 364 additions and 0 deletions

View File

@@ -984,6 +984,18 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name=".content.InstallApk" android:label="@string/activity_install_apk"
android:enabled="@bool/atLeastHoneycombMR2">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.SAMPLE_CODE" />
</intent-filter>
</activity>
<provider android:name=".content.FileProvider"
android:authorities="com.example.android.apis.content.FileProvider"
android:enabled="@bool/atLeastHoneycombMR2" />
<!-- ************************************* --> <!-- ************************************* -->
<!-- OS PACKAGE SAMPLES --> <!-- OS PACKAGE SAMPLES -->
<!-- ************************************* --> <!-- ************************************* -->

Binary file not shown.

View File

@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2007 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.
-->
<!-- Demonstrates starting and stopping a local service.
See corresponding Java code com.android.sdk.app.LocalSerice.java. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="4dip"
android:gravity="center_horizontal"
android:layout_width="match_parent" android:layout_height="match_parent">
<TextView
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_weight="0"
android:paddingBottom="4dip"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Demonstrates using the INSTALL_PACKAGE Intent to install an application."/>
<Button android:id="@+id/unknown_source"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="Unknown Source">
</Button>
<Button android:id="@+id/my_source"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="My Source">
</Button>
<Button android:id="@+id/replace"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="Replace">
</Button>
<Button android:id="@+id/uninstall"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="Uninstall">
</Button>
<Button android:id="@+id/uninstall_result"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:text="Uninstall w/Result">
</Button>
</LinearLayout>

View File

@@ -363,6 +363,8 @@
<string name="pick_phone">Pick a Phone</string> <string name="pick_phone">Pick a Phone</string>
<string name="pick_address">Pick an Address</string> <string name="pick_address">Pick an Address</string>
<string name="activity_install_apk">Content/Packages/Install Apk</string>
<!-- ============================== --> <!-- ============================== -->
<!-- app/intents examples strings --> <!-- app/intents examples strings -->
<!-- ============================== --> <!-- ============================== -->

View File

@@ -0,0 +1,115 @@
/*
* Copyright (C) 2011 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.example.android.apis.content;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.ContentProvider.PipeDataWriter;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.util.Log;
/**
* A very simple content provider that can serve arbitrary asset files from
* our .apk.
*/
public class FileProvider extends ContentProvider
implements PipeDataWriter<InputStream> {
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
// Don't support queries.
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// Don't support inserts.
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// Don't support deletes.
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// Don't support updates.
return 0;
}
@Override
public String getType(Uri uri) {
// For this sample, assume all files are .apks.
return "application/vnd.android.package-archive";
}
@Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
// Try to open an asset with the given name.
try {
InputStream is = getContext().getAssets().open(uri.getPath());
// Start a new thread that pipes the stream data back to the caller.
return new AssetFileDescriptor(
openPipeHelper(uri, null, null, is, this), 0,
AssetFileDescriptor.UNKNOWN_LENGTH);
} catch (IOException e) {
FileNotFoundException fnf = new FileNotFoundException("Unable to open " + uri);
throw fnf;
}
}
@Override
public void writeDataToPipe(ParcelFileDescriptor output, Uri uri, String mimeType,
Bundle opts, InputStream args) {
// Transfer data from the asset to the pipe the client is reading.
byte[] buffer = new byte[8192];
int n;
FileOutputStream fout = new FileOutputStream(output.getFileDescriptor());
try {
while ((n=args.read(buffer)) >= 0) {
fout.write(buffer, 0, n);
}
} catch (IOException e) {
Log.i("InstallApk", "Failed transferring", e);
} finally {
try {
args.close();
} catch (IOException e) {
}
try {
fout.close();
} catch (IOException e) {
}
}
}
}

View File

@@ -0,0 +1,179 @@
/*
* Copyright (C) 2011 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.example.android.apis.content;
// Need the following import to get access to the app resources, since this
// class is in a sub-package.
import com.example.android.apis.R;
import android.app.Activity;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.ContentProvider.PipeDataWriter;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Demonstration of styled text resources.
*/
public class InstallApk extends Activity {
static final int REQUEST_INSTALL = 1;
static final int REQUEST_UNINSTALL = 2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.install_apk);
// Watch for button clicks.
Button button = (Button)findViewById(R.id.unknown_source);
button.setOnClickListener(mUnknownSourceListener);
button = (Button)findViewById(R.id.my_source);
button.setOnClickListener(mMySourceListener);
button = (Button)findViewById(R.id.replace);
button.setOnClickListener(mReplaceListener);
button = (Button)findViewById(R.id.uninstall);
button.setOnClickListener(mUninstallListener);
button = (Button)findViewById(R.id.uninstall_result);
button.setOnClickListener(mUninstallResultListener);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == REQUEST_INSTALL) {
if (resultCode == Activity.RESULT_OK) {
Toast.makeText(this, "Install succeeded!", Toast.LENGTH_SHORT).show();
} else if (resultCode == Activity.RESULT_CANCELED) {
Toast.makeText(this, "Install canceled!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Install Failed!", Toast.LENGTH_SHORT).show();
}
} else if (requestCode == REQUEST_UNINSTALL) {
if (resultCode == Activity.RESULT_OK) {
Toast.makeText(this, "Uninstall succeeded!", Toast.LENGTH_SHORT).show();
} else if (resultCode == Activity.RESULT_CANCELED) {
Toast.makeText(this, "Uninstall canceled!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Uninstall Failed!", Toast.LENGTH_SHORT).show();
}
}
}
private OnClickListener mUnknownSourceListener = new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(Uri.fromFile(prepareApk("HelloActivity.apk")));
startActivity(intent);
}
};
private OnClickListener mMySourceListener = new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(Uri.fromFile(prepareApk("HelloActivity.apk")));
intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true);
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
intent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
getApplicationInfo().packageName);
startActivityForResult(intent, REQUEST_INSTALL);
}
};
private OnClickListener mReplaceListener = new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(Uri.fromFile(prepareApk("HelloActivity.apk")));
intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true);
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
intent.putExtra(Intent.EXTRA_ALLOW_REPLACE, true);
intent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
getApplicationInfo().packageName);
startActivityForResult(intent, REQUEST_INSTALL);
}
};
private OnClickListener mUninstallListener = new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
intent.setData(Uri.parse(
"package:com.example.android.helloactivity"));
startActivity(intent);
}
};
private OnClickListener mUninstallResultListener = new OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
intent.setData(Uri.parse(
"package:com.example.android.helloactivity"));
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
startActivityForResult(intent, REQUEST_UNINSTALL);
}
};
private File prepareApk(String assetName) {
// Copy the given asset out into a file so that it can be installed.
// Returns the path to the file.
byte[] buffer = new byte[8192];
InputStream is = null;
FileOutputStream fout = null;
try {
is = getAssets().open(assetName);
fout = openFileOutput("tmp.apk", Context.MODE_WORLD_READABLE);
int n;
while ((n=is.read(buffer)) >= 0) {
fout.write(buffer, 0, n);
}
} catch (IOException e) {
Log.i("InstallApk", "Failed transferring", e);
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
}
try {
if (fout != null) {
fout.close();
}
} catch (IOException e) {
}
}
return getFileStreamPath("tmp.apk");
}
}