diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml index 7b3fabd34..a26bb8880 100644 --- a/samples/ApiDemos/AndroidManifest.xml +++ b/samples/ApiDemos/AndroidManifest.xml @@ -984,6 +984,18 @@ + + + + + + + + + diff --git a/samples/ApiDemos/assets/HelloActivity.apk b/samples/ApiDemos/assets/HelloActivity.apk new file mode 100644 index 000000000..4e4b4875a Binary files /dev/null and b/samples/ApiDemos/assets/HelloActivity.apk differ diff --git a/samples/ApiDemos/res/layout/install_apk.xml b/samples/ApiDemos/res/layout/install_apk.xml new file mode 100644 index 000000000..1482d2c3a --- /dev/null +++ b/samples/ApiDemos/res/layout/install_apk.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/samples/ApiDemos/res/values/strings.xml b/samples/ApiDemos/res/values/strings.xml index ddf7e39f5..45d47554f 100644 --- a/samples/ApiDemos/res/values/strings.xml +++ b/samples/ApiDemos/res/values/strings.xml @@ -363,6 +363,8 @@ Pick a Phone Pick an Address + Content/Packages/Install Apk + diff --git a/samples/ApiDemos/src/com/example/android/apis/content/FileProvider.java b/samples/ApiDemos/src/com/example/android/apis/content/FileProvider.java new file mode 100644 index 000000000..156625a67 --- /dev/null +++ b/samples/ApiDemos/src/com/example/android/apis/content/FileProvider.java @@ -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 { + @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) { + } + } + } +} diff --git a/samples/ApiDemos/src/com/example/android/apis/content/InstallApk.java b/samples/ApiDemos/src/com/example/android/apis/content/InstallApk.java new file mode 100644 index 000000000..9036ee031 --- /dev/null +++ b/samples/ApiDemos/src/com/example/android/apis/content/InstallApk.java @@ -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"); + } +}