Query to detect exposure of sensitive information from android file intent

This commit is contained in:
luchua-bc
2021-08-29 18:52:33 +00:00
committed by Chris Smowton
parent d0b307ecfb
commit 0621e65827
20 changed files with 2173 additions and 2 deletions

View File

@@ -0,0 +1,64 @@
/** Provides Android sink models related to file creation. */
import java
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.ExternalFlow
import semmle.code.java.frameworks.android.Android
import semmle.code.java.frameworks.android.Intent
/** A sink representing methods creating a file in Android. */
class AndroidFileSink extends DataFlow::Node {
AndroidFileSink() { sinkNode(this, "create-file") }
}
/**
* The Android class `android.os.AsyncTask` for running tasks off the UI thread to achieve
* better user experience.
*/
class AsyncTask extends RefType {
AsyncTask() { this.hasQualifiedName("android.os", "AsyncTask") }
}
/** The `execute` method of Android `AsyncTask`. */
class AsyncTaskExecuteMethod extends Method {
AsyncTaskExecuteMethod() {
this.getDeclaringType().getSourceDeclaration().getASourceSupertype*() instanceof AsyncTask and
this.getName() = "execute"
}
int getParamIndex() { result = 0 }
}
/** The `executeOnExecutor` method of Android `AsyncTask`. */
class AsyncTaskExecuteOnExecutorMethod extends Method {
AsyncTaskExecuteOnExecutorMethod() {
this.getDeclaringType().getSourceDeclaration().getASourceSupertype*() instanceof AsyncTask and
this.getName() = "executeOnExecutor"
}
int getParamIndex() { result = 1 }
}
/** The `doInBackground` method of Android `AsyncTask`. */
class AsyncTaskRunInBackgroundMethod extends Method {
AsyncTaskRunInBackgroundMethod() {
this.getDeclaringType().getSourceDeclaration().getASourceSupertype*() instanceof AsyncTask and
this.getName() = "doInBackground"
}
}
/** The service start method of Android context. */
class ContextStartServiceMethod extends Method {
ContextStartServiceMethod() {
this.getName() = ["startService", "startForegroundService"] and
this.getDeclaringType().getASupertype*() instanceof TypeContext
}
}
/** The `onStartCommand` method of Android service. */
class ServiceOnStartCommandMethod extends Method {
ServiceOnStartCommandMethod() {
this.hasName("onStartCommand") and
this.getDeclaringType() instanceof AndroidService
}
}

View File

@@ -0,0 +1,118 @@
/** Provides summary models relating to file content inputs of Android. */
import java
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.frameworks.android.Android
/** The `startActivityForResult` method of Android `Activity`. */
class StartActivityForResultMethod extends Method {
StartActivityForResultMethod() {
this.getDeclaringType().getASupertype*() instanceof AndroidActivity and
this.getName() = "startActivityForResult"
}
}
/** Android class instance of `GET_CONTENT` intent. */
class GetContentIntent extends ClassInstanceExpr {
GetContentIntent() {
this.getConstructedType().getASupertype*() instanceof TypeIntent and
this.getArgument(0).(CompileTimeConstantExpr).getStringValue() =
"android.intent.action.GET_CONTENT"
or
exists(Field f |
this.getArgument(0) = f.getAnAccess() and
f.hasName("ACTION_GET_CONTENT") and
f.getDeclaringType() instanceof TypeIntent
)
}
}
/** Android intent data model in the new CSV format. */
private class AndroidIntentDataModel extends SummaryModelCsv {
override predicate row(string row) {
row =
[
"android.content;Intent;true;addCategory;;;Argument[-1];ReturnValue;taint",
"android.content;Intent;true;addFlags;;;Argument[-1];ReturnValue;taint",
"android.content;Intent;true;createChooser;;;Argument[0];ReturnValue;taint",
"android.content;Intent;true;getData;;;Argument[-1];ReturnValue;taint",
"android.content;Intent;true;getDataString;;;Argument[-1];ReturnValue;taint",
"android.content;Intent;true;getExtras;;;Argument[-1];ReturnValue;taint",
"android.content;Intent;true;getIntent;;;Argument[-1];ReturnValue;taint",
"android.content;Intent;true;get" +
[
"ParcelableArray", "ParcelableArrayList", "Parcelable", "Serializable", "StringArray",
"StringArrayList", "String"
] + "Extra;;;Argument[-1..1];ReturnValue;taint",
"android.content;Intent;true;put" +
[
"", "CharSequenceArrayList", "IntegerArrayList", "ParcelableArrayList",
"StringArrayList"
] + "Extra;;;Argument[1];Argument[-1];taint",
"android.content;Intent;true;putExtras;;;Argument[1];Argument[-1];taint",
"android.content;Intent;true;setData;;;Argument[0];ReturnValue;taint",
"android.content;Intent;true;setDataAndType;;;Argument[-1];ReturnValue;taint",
"android.content;Intent;true;setFlags;;;Argument[-1];ReturnValue;taint",
"android.content;Intent;true;setType;;;Argument[-1];ReturnValue;taint",
"android.net;Uri;true;getEncodedPath;;;Argument[-1];ReturnValue;taint",
"android.net;Uri;true;getEncodedQuery;;;Argument[-1];ReturnValue;taint",
"android.net;Uri;true;getLastPathSegment;;;Argument[-1];ReturnValue;taint",
"android.net;Uri;true;getPath;;;Argument[-1];ReturnValue;taint",
"android.net;Uri;true;getPathSegments;;;Argument[-1];ReturnValue;taint",
"android.net;Uri;true;getQuery;;;Argument[-1];ReturnValue;taint",
"android.net;Uri;true;getQueryParameter;;;Argument[-1];ReturnValue;taint",
"android.net;Uri;true;getQueryParameters;;;Argument[-1];ReturnValue;taint",
"android.os;AsyncTask;true;execute;;;Argument[0];ReturnValue;taint",
"android.os;AsyncTask;true;doInBackground;;;Argument[0];ReturnValue;taint"
]
}
}
/** Taint configuration for getting content intent. */
class GetContentIntentConfig extends TaintTracking::Configuration {
GetContentIntentConfig() { this = "GetContentIntentConfig" }
override predicate isSource(DataFlow::Node src) {
exists(GetContentIntent gi | src.asExpr() = gi)
}
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess ma |
ma.getMethod() instanceof StartActivityForResultMethod and sink.asExpr() = ma.getArgument(0)
)
}
}
/** Android `Intent` input to request file loading. */
class AndroidFileIntentInput extends LocalUserInput {
MethodAccess ma;
AndroidFileIntentInput() {
this.asExpr() = ma.getArgument(0) and
ma.getMethod() instanceof StartActivityForResultMethod and
exists(GetContentIntentConfig cc, GetContentIntent gi |
cc.hasFlow(DataFlow::exprNode(gi), DataFlow::exprNode(ma.getArgument(0)))
)
}
/** The request code identifying a specific intent, which is to be matched in `onActivityResult()`. */
int getRequestCode() { result = ma.getArgument(1).(CompileTimeConstantExpr).getIntValue() }
}
/** The `onActivityForResult` method of Android `Activity` */
class OnActivityForResultMethod extends Method {
OnActivityForResultMethod() {
this.getDeclaringType().getASupertype*() instanceof AndroidActivity and
this.getName() = "onActivityResult"
}
}
/** Input of Android activity result from the same application or another application. */
class AndroidActivityResultInput extends DataFlow::Node {
OnActivityForResultMethod m;
AndroidActivityResultInput() { this.asExpr() = m.getParameter(2).getAnAccess() }
/** The request code matching a specific intent request. */
VarAccess getRequestCodeVar() { result = m.getParameter(0).getAnAccess() }
}

View File

@@ -0,0 +1,31 @@
public class LoadFileFromAppActivity extends Activity {
public static final int REQUEST_CODE__SELECT_CONTENT_FROM_APPS = 99;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == LoadFileFromAppActivity.REQUEST_CODE__SELECT_CONTENT_FROM_APPS &&
resultCode == RESULT_OK) {
{
// BAD: Load file without validation
loadOfContentFromApps(data, resultCode);
}
{
// GOOD: load file with validation
if (!data.getData().getPath().startsWith("/data/data")) {
loadOfContentFromApps(data, resultCode);
}
}
}
}
private void loadOfContentFromApps(Intent contentIntent, int resultCode) {
Uri streamsToUpload = contentIntent.getData();
try {
RandomAccessFile file = new RandomAccessFile(streamsToUpload.getPath(), "r");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

View File

@@ -0,0 +1,38 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>The Android API allows to start an activity in another mobile application and receive a result back.
When starting an activity to retrieve a file from another application, missing input validation can
lead to leaking of sensitive configuration file or user data because the intent is from the application
itself that is allowed to access its protected data therefore bypassing the access control.
</p>
</overview>
<recommendation>
<p>
When loading file data from an activity of another application, validate that the file path is not its own
protected directory, which is a subdirectory of the Android application directory <code>/data/data/</code>.
</p>
</recommendation>
<example>
<p>
The following examples show the bad situation and the good situation respectively. In bad situation, a
file is loaded without path validation. In good situation, a file is loaded with path validation.
</p>
<sample src="LoadFileFromAppActivity.java" />
</example>
<references>
<li>
Google:
<a href="https://developer.android.com/training/basics/intents">Android: Interacting with Other Apps</a>.
</li>
<li>
CVE:
<a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-32695">CVE-2021-32695: File Sharing Flow Initiated by a Victim Leaks Sensitive Data to a Malicious App</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,78 @@
/**
* @name Leaking sensitive Android file
* @description Getting file intent from user input without path validation could leak arbitrary
* Android configuration file and sensitive user data.
* @kind path-problem
* @id java/sensitive_android_file_leak
* @tags security
* external/cwe/cwe-200
*/
import java
import AndroidFileIntentSink
import AndroidFileIntentSource
import DataFlow2::PathGraph
import semmle.code.java.dataflow.TaintTracking2
class AndroidFileLeakConfig extends TaintTracking2::Configuration {
AndroidFileLeakConfig() { this = "AndroidFileLeakConfig" }
/** Holds if it is an access to file intent result. */
override predicate isSource(DataFlow2::Node src) {
exists(
AndroidActivityResultInput ai, AndroidFileIntentInput fi, IfStmt ifs, VarAccess intentVar // if (requestCode == REQUEST_CODE__SELECT_CONTENT_FROM_APPS)
|
ifs.getCondition().getAChildExpr().getAChildExpr().(CompileTimeConstantExpr).getIntValue() =
fi.getRequestCode() and
ifs.getCondition().getAChildExpr().getAChildExpr() = ai.getRequestCodeVar() and
intentVar.getType() instanceof TypeIntent and
intentVar.(Argument).getAnEnclosingStmt() = ifs.getThen() and
src.asExpr() = intentVar
)
}
/** Holds if it is a sink of file access in Android. */
override predicate isSink(DataFlow2::Node sink) { sink instanceof AndroidFileSink }
override predicate isAdditionalTaintStep(DataFlow2::Node prev, DataFlow2::Node succ) {
exists(MethodAccess aema, AsyncTaskRunInBackgroundMethod arm |
// fileAsyncTask.execute(params) will invoke doInBackground(params) of FileAsyncTask
aema.getQualifier().getType() = arm.getDeclaringType() and
(
aema.getMethod() instanceof AsyncTaskExecuteMethod and
prev.asExpr() = aema.getArgument(0)
or
aema.getMethod() instanceof AsyncTaskExecuteOnExecutorMethod and
prev.asExpr() = aema.getArgument(1)
) and
succ.asExpr() = arm.getParameter(0).getAnAccess()
)
or
exists(MethodAccess csma, ServiceOnStartCommandMethod ssm, ClassInstanceExpr ce |
csma.getMethod() instanceof ContextStartServiceMethod and
ce.getConstructedType() instanceof TypeIntent and // Intent intent = new Intent(context, FileUploader.class);
ce.getArgument(1).getType().(ParameterizedType).getTypeArgument(0) = ssm.getDeclaringType() and
DataFlow2::localExprFlow(ce, csma.getArgument(0)) and // context.startService(intent);
prev.asExpr() = csma.getArgument(0) and
succ.asExpr() = ssm.getParameter(0).getAnAccess() // public int onStartCommand(Intent intent, int flags, int startId) {...} in FileUploader
)
}
override predicate isSanitizer(DataFlow2::Node node) {
exists(
MethodAccess startsWith // "startsWith" path check
|
startsWith.getMethod().hasName("startsWith") and
(
DataFlow2::localExprFlow(node.asExpr(), startsWith.getQualifier()) or
DataFlow2::localExprFlow(node.asExpr(),
startsWith.getQualifier().(MethodAccess).getQualifier())
)
)
}
}
from DataFlow2::PathNode source, DataFlow2::PathNode sink, AndroidFileLeakConfig conf
where conf.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Leaking arbitrary Android file from $@.", source.getNode(),
"this user input"

View File

@@ -0,0 +1,64 @@
import java.io.FileOutputStream;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.AsyncTask;
public class FileService extends Service {
public static String KEY_LOCAL_FILE = "local_file";
/**
* Service initialization
*/
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String localPath = intent.getStringExtra(KEY_LOCAL_FILE);
CopyAndUploadContentUrisTask copyTask = new CopyAndUploadContentUrisTask();
copyTask.execute(
copyTask.makeParamsToExecute(localPath)
);
return 2;
}
public class CopyAndUploadContentUrisTask extends AsyncTask<Object, Void, String> {
public Object[] makeParamsToExecute(
String sourceUri
) {
return new Object[] {
sourceUri
};
}
@Override
protected String doInBackground(Object[] params) {
FileOutputStream outputStream = null;
try {
String[] uris = (String[]) params[1];
outputStream = new FileOutputStream(uris[0]);
return "success";
} catch (Exception e) {
}
return "failure";
}
@Override
protected void onPostExecute(String result) {
}
@Override
protected void onPreExecute() {
}
@Override
protected void onProgressUpdate(Void... values) {
}
}
}

View File

@@ -0,0 +1,20 @@
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class GetFileActivity extends Activity {
public static final int REQUEST_CODE__SELECT_CONTENT_FROM_APPS = 99;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(-1);
Intent action = new Intent(Intent.ACTION_GET_CONTENT);
action = action.setType("*/*").addCategory(Intent.CATEGORY_OPENABLE);
action.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(
Intent.createChooser(action, "Open File From Selected Application"), REQUEST_CODE__SELECT_CONTENT_FROM_APPS
);
}
}

View File

@@ -0,0 +1,26 @@
import java.io.RandomAccessFile;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
public class LeakFileActivity extends Activity {
@Override
// BAD: Load file from activity without validation
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == GetFileActivity.REQUEST_CODE__SELECT_CONTENT_FROM_APPS &&
resultCode == RESULT_OK) {
loadOfContentFromApps(data, resultCode);
}
}
private void loadOfContentFromApps(Intent contentIntent, int resultCode) {
Uri streamsToUpload = contentIntent.getData();
try {
RandomAccessFile file = new RandomAccessFile(streamsToUpload.getPath(), "r");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

View File

@@ -0,0 +1,19 @@
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
public class LeakFileActivity2 extends Activity {
@Override
// BAD: Load file in a service without validation
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Uri localPath = data.getData();
if (requestCode == GetFileActivity.REQUEST_CODE__SELECT_CONTENT_FROM_APPS &&
resultCode == RESULT_OK) {
Intent intent = new Intent(this, FileService.class);
intent.putExtra(FileService.KEY_LOCAL_FILE, localPath);
startService(intent);
}
}
}

View File

@@ -0,0 +1,28 @@
import java.io.RandomAccessFile;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
public class SafeFileActivity extends Activity {
@Override
// GOOD: Load file from activity with path validation
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == GetFileActivity.REQUEST_CODE__SELECT_CONTENT_FROM_APPS &&
resultCode == RESULT_OK) {
safeLoadOfContentFromApps(data, resultCode);
}
}
private void safeLoadOfContentFromApps(Intent contentIntent, int resultCode) {
Uri streamsToUpload = contentIntent.getData();
try {
if (!streamsToUpload.getPath().startsWith("/data/data")) {
RandomAccessFile file = new RandomAccessFile(streamsToUpload.getPath(), "r");
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

View File

@@ -0,0 +1,34 @@
edges
| FileService.java:21:28:21:33 | intent : Intent | FileService.java:21:28:21:64 | getStringExtra(...) : String |
| FileService.java:21:28:21:33 | intent : Intent | FileService.java:25:42:25:50 | localPath : String |
| FileService.java:21:28:21:64 | getStringExtra(...) : String | FileService.java:25:42:25:50 | localPath : String |
| FileService.java:25:13:25:51 | makeParamsToExecute(...) : Object[] | FileService.java:44:44:44:49 | params : Object[] |
| FileService.java:25:13:25:51 | makeParamsToExecute(...) [[]] : String | FileService.java:25:13:25:51 | makeParamsToExecute(...) : Object[] |
| FileService.java:25:42:25:50 | localPath : String | FileService.java:25:13:25:51 | makeParamsToExecute(...) [[]] : String |
| FileService.java:44:33:44:52 | (...)... : Object | FileService.java:45:53:45:59 | ...[...] |
| FileService.java:44:44:44:49 | params : Object[] | FileService.java:44:33:44:52 | (...)... : Object |
| LeakFileActivity2.java:16:26:16:31 | intent : Intent | FileService.java:21:28:21:33 | intent : Intent |
| LeakFileActivity.java:14:35:14:38 | data : Intent | LeakFileActivity.java:18:40:18:59 | contentIntent : Intent |
| LeakFileActivity.java:18:40:18:59 | contentIntent : Intent | LeakFileActivity.java:19:31:19:43 | contentIntent : Intent |
| LeakFileActivity.java:19:31:19:43 | contentIntent : Intent | LeakFileActivity.java:19:31:19:53 | getData(...) : Uri |
| LeakFileActivity.java:19:31:19:53 | getData(...) : Uri | LeakFileActivity.java:21:58:21:72 | streamsToUpload : Uri |
| LeakFileActivity.java:21:58:21:72 | streamsToUpload : Uri | LeakFileActivity.java:21:58:21:82 | getPath(...) |
nodes
| FileService.java:21:28:21:33 | intent : Intent | semmle.label | intent : Intent |
| FileService.java:21:28:21:64 | getStringExtra(...) : String | semmle.label | getStringExtra(...) : String |
| FileService.java:25:13:25:51 | makeParamsToExecute(...) : Object[] | semmle.label | makeParamsToExecute(...) : Object[] |
| FileService.java:25:13:25:51 | makeParamsToExecute(...) [[]] : String | semmle.label | makeParamsToExecute(...) [[]] : String |
| FileService.java:25:42:25:50 | localPath : String | semmle.label | localPath : String |
| FileService.java:44:33:44:52 | (...)... : Object | semmle.label | (...)... : Object |
| FileService.java:44:44:44:49 | params : Object[] | semmle.label | params : Object[] |
| FileService.java:45:53:45:59 | ...[...] | semmle.label | ...[...] |
| LeakFileActivity2.java:16:26:16:31 | intent : Intent | semmle.label | intent : Intent |
| LeakFileActivity.java:14:35:14:38 | data : Intent | semmle.label | data : Intent |
| LeakFileActivity.java:18:40:18:59 | contentIntent : Intent | semmle.label | contentIntent : Intent |
| LeakFileActivity.java:19:31:19:43 | contentIntent : Intent | semmle.label | contentIntent : Intent |
| LeakFileActivity.java:19:31:19:53 | getData(...) : Uri | semmle.label | getData(...) : Uri |
| LeakFileActivity.java:21:58:21:72 | streamsToUpload : Uri | semmle.label | streamsToUpload : Uri |
| LeakFileActivity.java:21:58:21:82 | getPath(...) | semmle.label | getPath(...) |
#select
| FileService.java:45:53:45:59 | ...[...] | LeakFileActivity2.java:16:26:16:31 | intent : Intent | FileService.java:45:53:45:59 | ...[...] | Leaking arbitrary Android file from $@. | LeakFileActivity2.java:16:26:16:31 | intent | this user input |
| LeakFileActivity.java:21:58:21:82 | getPath(...) | LeakFileActivity.java:14:35:14:38 | data : Intent | LeakFileActivity.java:21:58:21:82 | getPath(...) | Leaking arbitrary Android file from $@. | LeakFileActivity.java:14:35:14:38 | data | this user input |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-200/SensitiveAndroidFileLeak.ql

View File

@@ -0,0 +1 @@
// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/google-android-9.0.0

View File

@@ -15,6 +15,8 @@
*/ */
package android.app; package android.app;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
@@ -675,7 +677,16 @@ import android.view.View;
* upload, independent of whether the original activity is paused, stopped, or * upload, independent of whether the original activity is paused, stopped, or
* finished. * finished.
*/ */
public class Activity { public class Activity extends ContextWrapper {
/** Standard activity result: operation canceled. */
public static final int RESULT_CANCELED = 0;
/** Standard activity result: operation succeeded. */
public static final int RESULT_OK = -1;
/** Start of user-defined activity results. */
public static final int RESULT_FIRST_USER = 1;
/** Return the intent that started this activity. */ /** Return the intent that started this activity. */
public Intent getIntent() { public Intent getIntent() {
return null; return null;
@@ -1142,4 +1153,37 @@ public class Activity {
*/ */
public void startActivities(Intent[] intents, Bundle options) { public void startActivities(Intent[] intents, Bundle options) {
} }
/**
* Called when an activity you launched exits, giving you the requestCode
* you started it with, the resultCode it returned, and any additional
* data from it. The <var>resultCode</var> will be
* {@link #RESULT_CANCELED} if the activity explicitly returned that,
* didn't return any result, or crashed during its operation.
*
* <p>An activity can never receive a result in the resumed state. You can count on
* {@link #onResume} being called after this method, though not necessarily immediately after.
* If the activity was resumed, it will be paused and the result will be delivered, followed
* by {@link #onResume}. If the activity wasn't in the resumed state, then the result will
* be delivered, with {@link #onResume} called sometime later when the activity becomes active
* again.
*
* <p>This method is never invoked if your activity sets
* {@link android.R.styleable#AndroidManifestActivity_noHistory noHistory} to
* <code>true</code>.
*
* @param requestCode The integer request code originally supplied to
* startActivityForResult(), allowing you to identify who this
* result came from.
* @param resultCode The integer result code returned by the child activity
* through its setResult().
* @param data An Intent, which can return result data to the caller
* (various data can be attached to Intent "extras").
*
* @see #startActivityForResult
* @see #createPendingResult
* @see #setResult(int)
*/
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
}
} }

View File

@@ -0,0 +1,344 @@
/*
* Copyright (C) 2006 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;
import android.content.Intent;
import android.content.ContextWrapper;
/**
* A Service is an application component representing either an application's desire
* to perform a longer-running operation while not interacting with the user
* or to supply functionality for other applications to use. Each service
* class must have a corresponding
* {@link android.R.styleable#AndroidManifestService &lt;service&gt;}
* declaration in its package's <code>AndroidManifest.xml</code>. Services
* can be started with
* {@link android.content.Context#startService Context.startService()} and
* {@link android.content.Context#bindService Context.bindService()}.
*
* <p>Note that services, like other application objects, run in the main
* thread of their hosting process. This means that, if your service is going
* to do any CPU intensive (such as MP3 playback) or blocking (such as
* networking) operations, it should spawn its own thread in which to do that
* work. More information on this can be found in
* <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">Processes and
* Threads</a>. The {@link IntentService} class is available
* as a standard implementation of Service that has its own thread where it
* schedules its work to be done.</p>
*
* <p>Topics covered here:
* <ol>
* <li><a href="#WhatIsAService">What is a Service?</a>
* <li><a href="#ServiceLifecycle">Service Lifecycle</a>
* <li><a href="#Permissions">Permissions</a>
* <li><a href="#ProcessLifecycle">Process Lifecycle</a>
* <li><a href="#LocalServiceSample">Local Service Sample</a>
* <li><a href="#RemoteMessengerServiceSample">Remote Messenger Service Sample</a>
* </ol>
*
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For a detailed discussion about how to create services, read the
* <a href="{@docRoot}guide/topics/fundamentals/services.html">Services</a> developer guide.</p>
* </div>
*
* <a name="WhatIsAService"></a>
* <h3>What is a Service?</h3>
*
* <p>Most confusion about the Service class actually revolves around what
* it is <em>not</em>:</p>
*
* <ul>
* <li> A Service is <b>not</b> a separate process. The Service object itself
* does not imply it is running in its own process; unless otherwise specified,
* it runs in the same process as the application it is part of.
* <li> A Service is <b>not</b> a thread. It is not a means itself to do work off
* of the main thread (to avoid Application Not Responding errors).
* </ul>
*
* <p>Thus a Service itself is actually very simple, providing two main features:</p>
*
* <ul>
* <li>A facility for the application to tell the system <em>about</em>
* something it wants to be doing in the background (even when the user is not
* directly interacting with the application). This corresponds to calls to
* {@link android.content.Context#startService Context.startService()}, which
* ask the system to schedule work for the service, to be run until the service
* or someone else explicitly stop it.
* <li>A facility for an application to expose some of its functionality to
* other applications. This corresponds to calls to
* {@link android.content.Context#bindService Context.bindService()}, which
* allows a long-standing connection to be made to the service in order to
* interact with it.
* </ul>
*
* <p>When a Service component is actually created, for either of these reasons,
* all that the system actually does is instantiate the component
* and call its {@link #onCreate} and any other appropriate callbacks on the
* main thread. It is up to the Service to implement these with the appropriate
* behavior, such as creating a secondary thread in which it does its work.</p>
*
* <p>Note that because Service itself is so simple, you can make your
* interaction with it as simple or complicated as you want: from treating it
* as a local Java object that you make direct method calls on (as illustrated
* by <a href="#LocalServiceSample">Local Service Sample</a>), to providing
* a full remoteable interface using AIDL.</p>
*
* <a name="ServiceLifecycle"></a>
* <h3>Service Lifecycle</h3>
*
* <p>There are two reasons that a service can be run by the system. If someone
* calls {@link android.content.Context#startService Context.startService()} then the system will
* retrieve the service (creating it and calling its {@link #onCreate} method
* if needed) and then call its {@link #onStartCommand} method with the
* arguments supplied by the client. The service will at this point continue
* running until {@link android.content.Context#stopService Context.stopService()} or
* {@link #stopSelf()} is called. Note that multiple calls to
* Context.startService() do not nest (though they do result in multiple corresponding
* calls to onStartCommand()), so no matter how many times it is started a service
* will be stopped once Context.stopService() or stopSelf() is called; however,
* services can use their {@link #stopSelf(int)} method to ensure the service is
* not stopped until started intents have been processed.
*
* <p>For started services, there are two additional major modes of operation
* they can decide to run in, depending on the value they return from
* onStartCommand(): {@link #START_STICKY} is used for services that are
* explicitly started and stopped as needed, while {@link #START_NOT_STICKY}
* or {@link #START_REDELIVER_INTENT} are used for services that should only
* remain running while processing any commands sent to them. See the linked
* documentation for more detail on the semantics.
*
* <p>Clients can also use {@link android.content.Context#bindService Context.bindService()} to
* obtain a persistent connection to a service. This likewise creates the
* service if it is not already running (calling {@link #onCreate} while
* doing so), but does not call onStartCommand(). The client will receive the
* {@link android.os.IBinder} object that the service returns from its
* {@link #onBind} method, allowing the client to then make calls back
* to the service. The service will remain running as long as the connection
* is established (whether or not the client retains a reference on the
* service's IBinder). Usually the IBinder returned is for a complex
* interface that has been <a href="{@docRoot}guide/components/aidl.html">written
* in aidl</a>.
*
* <p>A service can be both started and have connections bound to it. In such
* a case, the system will keep the service running as long as either it is
* started <em>or</em> there are one or more connections to it with the
* {@link android.content.Context#BIND_AUTO_CREATE Context.BIND_AUTO_CREATE}
* flag. Once neither
* of these situations hold, the service's {@link #onDestroy} method is called
* and the service is effectively terminated. All cleanup (stopping threads,
* unregistering receivers) should be complete upon returning from onDestroy().
*
* <a name="Permissions"></a>
* <h3>Permissions</h3>
*
* <p>Global access to a service can be enforced when it is declared in its
* manifest's {@link android.R.styleable#AndroidManifestService &lt;service&gt;}
* tag. By doing so, other applications will need to declare a corresponding
* {@link android.R.styleable#AndroidManifestUsesPermission &lt;uses-permission&gt;}
* element in their own manifest to be able to start, stop, or bind to
* the service.
*
* <p>As of {@link android.os.Build.VERSION_CODES#GINGERBREAD}, when using
* {@link Context#startService(Intent) Context.startService(Intent)}, you can
* also set {@link Intent#FLAG_GRANT_READ_URI_PERMISSION
* Intent.FLAG_GRANT_READ_URI_PERMISSION} and/or {@link Intent#FLAG_GRANT_WRITE_URI_PERMISSION
* Intent.FLAG_GRANT_WRITE_URI_PERMISSION} on the Intent. This will grant the
* Service temporary access to the specific URIs in the Intent. Access will
* remain until the Service has called {@link #stopSelf(int)} for that start
* command or a later one, or until the Service has been completely stopped.
* This works for granting access to the other apps that have not requested
* the permission protecting the Service, or even when the Service is not
* exported at all.
*
* <p>In addition, a service can protect individual IPC calls into it with
* permissions, by calling the
* {@link #checkCallingPermission}
* method before executing the implementation of that call.
*
* <p>See the <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
* document for more information on permissions and security in general.
*
* <a name="ProcessLifecycle"></a>
* <h3>Process Lifecycle</h3>
*
* <p>The Android system will attempt to keep the process hosting a service
* around as long as the service has been started or has clients bound to it.
* When running low on memory and needing to kill existing processes, the
* priority of a process hosting the service will be the higher of the
* following possibilities:
*
* <ul>
* <li><p>If the service is currently executing code in its
* {@link #onCreate onCreate()}, {@link #onStartCommand onStartCommand()},
* or {@link #onDestroy onDestroy()} methods, then the hosting process will
* be a foreground process to ensure this code can execute without
* being killed.
* <li><p>If the service has been started, then its hosting process is considered
* to be less important than any processes that are currently visible to the
* user on-screen, but more important than any process not visible. Because
* only a few processes are generally visible to the user, this means that
* the service should not be killed except in low memory conditions. However, since
* the user is not directly aware of a background service, in that state it <em>is</em>
* considered a valid candidate to kill, and you should be prepared for this to
* happen. In particular, long-running services will be increasingly likely to
* kill and are guaranteed to be killed (and restarted if appropriate) if they
* remain started long enough.
* <li><p>If there are clients bound to the service, then the service's hosting
* process is never less important than the most important client. That is,
* if one of its clients is visible to the user, then the service itself is
* considered to be visible. The way a client's importance impacts the service's
* importance can be adjusted through {@link Context#BIND_ABOVE_CLIENT},
* {@link Context#BIND_ALLOW_OOM_MANAGEMENT}, {@link Context#BIND_WAIVE_PRIORITY},
* {@link Context#BIND_IMPORTANT}, and {@link Context#BIND_ADJUST_WITH_ACTIVITY}.
* <li><p>A started service can use the {@link #startForeground(int, Notification)}
* API to put the service in a foreground state, where the system considers
* it to be something the user is actively aware of and thus not a candidate
* for killing when low on memory. (It is still theoretically possible for
* the service to be killed under extreme memory pressure from the current
* foreground application, but in practice this should not be a concern.)
* </ul>
*
* <p>Note this means that most of the time your service is running, it may
* be killed by the system if it is under heavy memory pressure. If this
* happens, the system will later try to restart the service. An important
* consequence of this is that if you implement {@link #onStartCommand onStartCommand()}
* to schedule work to be done asynchronously or in another thread, then you
* may want to use {@link #START_FLAG_REDELIVERY} to have the system
* re-deliver an Intent for you so that it does not get lost if your service
* is killed while processing it.
*
* <p>Other application components running in the same process as the service
* (such as an {@link android.app.Activity}) can, of course, increase the
* importance of the overall
* process beyond just the importance of the service itself.
*
* <a name="LocalServiceSample"></a>
* <h3>Local Service Sample</h3>
*
* <p>One of the most common uses of a Service is as a secondary component
* running alongside other parts of an application, in the same process as
* the rest of the components. All components of an .apk run in the same
* process unless explicitly stated otherwise, so this is a typical situation.
*
* <p>When used in this way, by assuming the
* components are in the same process, you can greatly simplify the interaction
* between them: clients of the service can simply cast the IBinder they
* receive from it to a concrete class published by the service.
*
* <p>An example of this use of a Service is shown here. First is the Service
* itself, publishing a custom class when bound:
*
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LocalService.java
* service}
*
* <p>With that done, one can now write client code that directly accesses the
* running service, such as:
*
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/LocalServiceActivities.java
* bind}
*
* <a name="RemoteMessengerServiceSample"></a>
* <h3>Remote Messenger Service Sample</h3>
*
* <p>If you need to be able to write a Service that can perform complicated
* communication with clients in remote processes (beyond simply the use of
* {@link Context#startService(Intent) Context.startService} to send
* commands to it), then you can use the {@link android.os.Messenger} class
* instead of writing full AIDL files.
*
* <p>An example of a Service that uses Messenger as its client interface
* is shown here. First is the Service itself, publishing a Messenger to
* an internal Handler when bound:
*
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/MessengerService.java
* service}
*
* <p>If we want to make this service run in a remote process (instead of the
* standard one for its .apk), we can use <code>android:process</code> in its
* manifest tag to specify one:
*
* {@sample development/samples/ApiDemos/AndroidManifest.xml remote_service_declaration}
*
* <p>Note that the name "remote" chosen here is arbitrary, and you can use
* other names if you want additional processes. The ':' prefix appends the
* name to your package's standard process name.
*
* <p>With that done, clients can now bind to the service and send messages
* to it. Note that this allows clients to register with it to receive
* messages back as well:
*
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/MessengerServiceActivities.java
* bind}
*/
public abstract class Service extends ContextWrapper {
/**
* Called by the system when the service is first created. Do not call this method directly.
*/
public void onCreate() {
}
/**
* @deprecated Implement {@link #onStartCommand(Intent, int, int)} instead.
*/
@Deprecated
public void onStart(Intent intent, int startId) {
}
/**
* Called by the system every time a client explicitly starts the service by calling
* {@link android.content.Context#startService}, providing the arguments it supplied and a
* unique integer token representing the start request. Do not call this method directly.
*
* <p>For backwards compatibility, the default implementation calls
* {@link #onStart} and returns either {@link #START_STICKY}
* or {@link #START_STICKY_COMPATIBILITY}.
*
* <p class="caution">Note that the system calls this on your
* service's main thread. A service's main thread is the same
* thread where UI operations take place for Activities running in the
* same process. You should always avoid stalling the main
* thread's event loop. When doing long-running operations,
* network calls, or heavy disk I/O, you should kick off a new
* thread, or use {@link android.os.AsyncTask}.</p>
*
* @param intent The Intent supplied to {@link android.content.Context#startService},
* as given. This may be null if the service is being restarted after
* its process has gone away, and it had previously returned anything
* except {@link #START_STICKY_COMPATIBILITY}.
* @param flags Additional data about this start request.
* @param startId A unique integer representing this specific request to
* start. Use with {@link #stopSelfResult(int)}.
*
* @return The return value indicates what semantics the system should
* use for the service's current started state. It may be one of the
* constants associated with the {@link #START_CONTINUATION_MASK} bits.
*
* @see #stopSelfResult(int)
*/
public int onStartCommand(Intent intent, int flags, int startId) {
return -1;
}
/**
* Called by the system to notify a Service that it is no longer used and is being removed. The
* service should clean up any resources it holds (threads, registered
* receivers, etc) at this point. Upon return, there will be no more calls
* in to this Service object and it is effectively dead. Do not call this method directly.
*/
public void onDestroy() {
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright (C) 2006 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.content;
/**
* Identifier for a specific application component
* ({@link android.app.Activity}, {@link android.app.Service},
* {@link android.content.BroadcastReceiver}, or
* {@link android.content.ContentProvider}) that is available. Two
* pieces of information, encapsulated here, are required to identify
* a component: the package (a String) it exists in, and the class (a String)
* name inside of that package.
*
*/
public final class ComponentName {
}

View File

@@ -961,4 +961,91 @@ public abstract class Context {
* @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
*/ */
public abstract void sendOrderedBroadcast(Intent intent, String receiverPermission); public abstract void sendOrderedBroadcast(Intent intent, String receiverPermission);
}
/**
* Request that a given application service be started. The Intent
* should either contain the complete class name of a specific service
* implementation to start, or a specific package name to target. If the
* Intent is less specified, it logs a warning about this. In this case any of the
* multiple matching services may be used. If this service
* is not already running, it will be instantiated and started (creating a
* process for it if needed); if it is running then it remains running.
*
* <p>Every call to this method will result in a corresponding call to
* the target service's {@link android.app.Service#onStartCommand} method,
* with the <var>intent</var> given here. This provides a convenient way
* to submit jobs to a service without having to bind and call on to its
* interface.
*
* <p>Using startService() overrides the default service lifetime that is
* managed by {@link #bindService}: it requires the service to remain
* running until {@link #stopService} is called, regardless of whether
* any clients are connected to it. Note that calls to startService()
* do not nest: no matter how many times you call startService(),
* a single call to {@link #stopService} will stop it.
*
* <p>The system attempts to keep running services around as much as
* possible. The only time they should be stopped is if the current
* foreground application is using so many resources that the service needs
* to be killed. If any errors happen in the service's process, it will
* automatically be restarted.
*
* <p>This function will throw {@link SecurityException} if you do not
* have permission to start the given service.
*
* <p class="note"><strong>Note:</strong> Each call to startService()
* results in significant work done by the system to manage service
* lifecycle surrounding the processing of the intent, which can take
* multiple milliseconds of CPU time. Due to this cost, startService()
* should not be used for frequent intent delivery to a service, and only
* for scheduling significant work. Use {@link #bindService bound services}
* for high frequency calls.
* </p>
*
* @param service Identifies the service to be started. The Intent must be
* fully explicit (supplying a component name). Additional values
* may be included in the Intent extras to supply arguments along with
* this specific start call.
*
* @return If the service is being started or is already running, the
* {@link ComponentName} of the actual service that was started is
* returned; else if the service does not exist null is returned.
*
* @throws SecurityException If the caller does not have permission to access the service
* or the service can not be found.
* @throws IllegalStateException If the application is in a state where the service
* can not be started (such as not in the foreground in a state when services are allowed).
*
* @see #stopService
* @see #bindService
*/
public abstract ComponentName startService(Intent service);
/**
* Similar to {@link #startService(Intent)}, but with an implicit promise that the
* Service will call {@link android.app.Service#startForeground(int, android.app.Notification)
* startForeground(int, android.app.Notification)} once it begins running. The service is given
* an amount of time comparable to the ANR interval to do this, otherwise the system
* will automatically stop the service and declare the app ANR.
*
* <p>Unlike the ordinary {@link #startService(Intent)}, this method can be used
* at any time, regardless of whether the app hosting the service is in a foreground
* state.
*
* @param service Identifies the service to be started. The Intent must be
* fully explicit (supplying a component name). Additional values
* may be included in the Intent extras to supply arguments along with
* this specific start call.
*
* @return If the service is being started or is already running, the
* {@link ComponentName} of the actual service that was started is
* returned; else if the service does not exist null is returned.
*
* @throws SecurityException If the caller does not have permission to access the service
* or the service can not be found.
*
* @see #stopService
* @see android.app.Service#startForeground(int, android.app.Notification)
*/
public abstract ComponentName startForegroundService(Intent service);
}

View File

@@ -0,0 +1,186 @@
/*
* Copyright (C) 2006 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.content;
import java.io.File;
import android.os.Bundle;
/**
* Proxying implementation of Context that simply delegates all of its calls to
* another Context. Can be subclassed to modify behavior without changing
* the original Context.
*/
public class ContextWrapper extends Context {
public ContextWrapper() {
}
public ContextWrapper(Context base) {
}
@Override
public Context getApplicationContext() {
return null;
}
@Override
public File getFileStreamPath(String name) {
return null;
}
@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
return null;
}
@Override
public File getSharedPrefsFile(String name) {
return null;
}
@Override
public String[] fileList() {
return null;
}
@Override
public File getDataDir() {
return null;
}
@Override
public File getFilesDir() {
return null;
}
@Override
public File getNoBackupFilesDir() {
return null;
}
@Override
public File getExternalFilesDir(String type) {
return null;
}
@Override
public File[] getExternalFilesDirs(String type) {
return null;
}
@Override
public File getObbDir() {
return null;
}
@Override
public File[] getObbDirs() {
return null;
}
@Override
public File getCacheDir() {
return null;
}
@Override
public File getCodeCacheDir() {
return null;
}
@Override
public File getExternalCacheDir() {
return null;
}
@Override
public File[] getExternalCacheDirs() {
return null;
}
@Override
public File[] getExternalMediaDirs() {
return null;
}
@Override
public File getDir(String name, int mode) {
return null;
}
/** @hide **/
@Override
public File getPreloadsFileCache() {
return null;
}
@Override
public void startActivity(Intent intent) {
}
/** @hide **/
public void startActivityForResult(
String who, Intent intent, int requestCode, Bundle options) {
}
/** @hide **/
public boolean canStartActivityForResult() {
return false;
}
@Override
public void startActivity(Intent intent, Bundle options) {
}
@Override
public void startActivities(Intent[] intents) {
}
@Override
public void startActivities(Intent[] intents, Bundle options) {
}
@Override
public void sendBroadcast(Intent intent) {
}
@Override
public void sendBroadcast(Intent intent, String receiverPermission) {
}
@Override
public void sendBroadcastWithMultiplePermissions(Intent intent, String[] receiverPermissions) {
}
/** @hide */
@Override
public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
}
@Override
public void sendOrderedBroadcast(Intent intent,
String receiverPermission) {
}
@Override
public ComponentName startService(Intent service) {
return null;
}
@Override
public ComponentName startForegroundService(Intent service) {
return null;
}
}

View File

@@ -723,6 +723,511 @@ import java.util.Set;
*/ */
public class Intent implements Parcelable, Cloneable { public class Intent implements Parcelable, Cloneable {
/**
* Activity Action: Start as a main entry point, does not expect to
* receive data.
* <p>Input: nothing
* <p>Output: nothing
*/
public static final String ACTION_MAIN = "android.intent.action.MAIN";
/**
* Activity Action: Display the data to the user. This is the most common
* action performed on data -- it is the generic action you can use on
* a piece of data to get the most reasonable thing to occur. For example,
* when used on a contacts entry it will view the entry; when used on a
* mailto: URI it will bring up a compose window filled with the information
* supplied by the URI; when used with a tel: URI it will invoke the
* dialer.
* <p>Input: {@link #getData} is URI from which to retrieve data.
* <p>Output: nothing.
*/
public static final String ACTION_VIEW = "android.intent.action.VIEW";
/**
* A synonym for {@link #ACTION_VIEW}, the "standard" action that is
* performed on a piece of data.
*/
public static final String ACTION_DEFAULT = ACTION_VIEW;
/**
* Used to indicate that some piece of data should be attached to some other
* place. For example, image data could be attached to a contact. It is up
* to the recipient to decide where the data should be attached; the intent
* does not specify the ultimate destination.
* <p>Input: {@link #getData} is URI of data to be attached.
* <p>Output: nothing.
*/
public static final String ACTION_ATTACH_DATA = "android.intent.action.ATTACH_DATA";
/**
* Activity Action: Provide explicit editable access to the given data.
* <p>Input: {@link #getData} is URI of data to be edited.
* <p>Output: nothing.
*/
public static final String ACTION_EDIT = "android.intent.action.EDIT";
/**
* Activity Action: Pick an existing item, or insert a new item, and then edit it.
* <p>Input: {@link #getType} is the desired MIME type of the item to create or edit.
* The extras can contain type specific data to pass through to the editing/creating
* activity.
* <p>Output: The URI of the item that was picked. This must be a content:
* URI so that any receiver can access it.
*/
public static final String ACTION_INSERT_OR_EDIT = "android.intent.action.INSERT_OR_EDIT";
/**
* Activity Action: Pick an item from the data, returning what was selected.
* <p>Input: {@link #getData} is URI containing a directory of data
* (vnd.android.cursor.dir/*) from which to pick an item.
* <p>Output: The URI of the item that was picked.
*/
public static final String ACTION_PICK = "android.intent.action.PICK";
/**
* Activity Action: Creates a shortcut.
* <p>Input: Nothing.</p>
* <p>Output: An Intent representing the shortcut. The intent must contain three
* extras: SHORTCUT_INTENT (value: Intent), SHORTCUT_NAME (value: String),
* and SHORTCUT_ICON (value: Bitmap) or SHORTCUT_ICON_RESOURCE
* (value: ShortcutIconResource).</p>
*
* @see #EXTRA_SHORTCUT_INTENT
* @see #EXTRA_SHORTCUT_NAME
* @see #EXTRA_SHORTCUT_ICON
* @see #EXTRA_SHORTCUT_ICON_RESOURCE
* @see android.content.Intent.ShortcutIconResource
*/
public static final String ACTION_CREATE_SHORTCUT = "android.intent.action.CREATE_SHORTCUT";
/**
* Activity Action: Display an activity chooser, allowing the user to pick
* what they want to before proceeding. This can be used as an alternative
* to the standard activity picker that is displayed by the system when
* you try to start an activity with multiple possible matches, with these
* differences in behavior:
* <ul>
* <li>You can specify the title that will appear in the activity chooser.
* <li>The user does not have the option to make one of the matching
* activities a preferred activity, and all possible activities will
* always be shown even if one of them is currently marked as the
* preferred activity.
* </ul>
* <p>
* This action should be used when the user will naturally expect to
* select an activity in order to proceed. An example if when not to use
* it is when the user clicks on a "mailto:" link. They would naturally
* expect to go directly to their mail app, so startActivity() should be
* called directly: it will
* either launch the current preferred app, or put up a dialog allowing the
* user to pick an app to use and optionally marking that as preferred.
* <p>
* In contrast, if the user is selecting a menu item to send a picture
* they are viewing to someone else, there are many different things they
* may want to do at this point: send it through e-mail, upload it to a
* web service, etc. In this case the CHOOSER action should be used, to
* always present to the user a list of the things they can do, with a
* nice title given by the caller such as "Send this photo with:".
* <p>
* As a convenience, an Intent of this form can be created with the
* {@link #createChooser} function.
* <p>Input: No data should be specified. get*Extra must have
* a {@link #EXTRA_INTENT} field containing the Intent being executed,
* and can optionally have a {@link #EXTRA_TITLE} field containing the
* title text to display in the chooser.
* <p>Output: Depends on the protocol of {@link #EXTRA_INTENT}.
*/
public static final String ACTION_CHOOSER = "android.intent.action.CHOOSER";
/**
* Convenience function for creating a {@link #ACTION_CHOOSER} Intent.
*
* @param target The Intent that the user will be selecting an activity
* to perform.
* @param title Optional title that will be displayed in the chooser.
* @return Return a new Intent object that you can hand to
* {@link Context#startActivity(Intent) Context.startActivity()} and
* related methods.
*/
public static Intent createChooser(Intent target, CharSequence title) {
return null;
}
/**
* Activity Action: Allow the user to select a particular kind of data and
* return it. This is different than {@link #ACTION_PICK} in that here we
* just say what kind of data is desired, not a URI of existing data from
* which the user can pick. A ACTION_GET_CONTENT could allow the user to
* create the data as it runs (for example taking a picture or recording a
* sound), let them browse over the web and download the desired data,
* etc.
* <p>
* There are two main ways to use this action: if you want a specific kind
* of data, such as a person contact, you set the MIME type to the kind of
* data you want and launch it with {@link Context#startActivity(Intent)}.
* The system will then launch the best application to select that kind
* of data for you.
* <p>
* You may also be interested in any of a set of types of content the user
* can pick. For example, an e-mail application that wants to allow the
* user to add an attachment to an e-mail message can use this action to
* bring up a list of all of the types of content the user can attach.
* <p>
* In this case, you should wrap the GET_CONTENT intent with a chooser
* (through {@link #createChooser}), which will give the proper interface
* for the user to pick how to send your data and allow you to specify
* a prompt indicating what they are doing. You will usually specify a
* broad MIME type (such as image/* or {@literal *}/*), resulting in a
* broad range of content types the user can select from.
* <p>
* When using such a broad GET_CONTENT action, it is often desirable to
* only pick from data that can be represented as a stream. This is
* accomplished by requiring the {@link #CATEGORY_OPENABLE} in the Intent.
* <p>
* Callers can optionally specify {@link #EXTRA_LOCAL_ONLY} to request that
* the launched content chooser only returns results representing data that
* is locally available on the device. For example, if this extra is set
* to true then an image picker should not show any pictures that are available
* from a remote server but not already on the local device (thus requiring
* they be downloaded when opened).
* <p>
* Input: {@link #getType} is the desired MIME type to retrieve. Note
* that no URI is supplied in the intent, as there are no constraints on
* where the returned data originally comes from. You may also include the
* {@link #CATEGORY_OPENABLE} if you can only accept data that can be
* opened as a stream. You may use {@link #EXTRA_LOCAL_ONLY} to limit content
* selection to local data.
* <p>
* Output: The URI of the item that was picked. This must be a content:
* URI so that any receiver can access it.
*/
public static final String ACTION_GET_CONTENT = "android.intent.action.GET_CONTENT";
/**
* Activity Action: Dial a number as specified by the data. This shows a
* UI with the number being dialed, allowing the user to explicitly
* initiate the call.
* <p>Input: If nothing, an empty dialer is started; else {@link #getData}
* is URI of a phone number to be dialed or a tel: URI of an explicit phone
* number.
* <p>Output: nothing.
*/
public static final String ACTION_DIAL = "android.intent.action.DIAL";
/**
* Activity Action: Perform a call to someone specified by the data.
* <p>Input: If nothing, an empty dialer is started; else {@link #getData}
* is URI of a phone number to be dialed or a tel: URI of an explicit phone
* number.
* <p>Output: nothing.
*
* <p>Note: there will be restrictions on which applications can initiate a
* call; most applications should use the {@link #ACTION_DIAL}.
* <p>Note: this Intent <strong>cannot</strong> be used to call emergency
* numbers. Applications can <strong>dial</strong> emergency numbers using
* {@link #ACTION_DIAL}, however.
*/
public static final String ACTION_CALL = "android.intent.action.CALL";
/**
* Activity Action: Perform a call to an emergency number specified by the
* data.
* <p>Input: {@link #getData} is URI of a phone number to be dialed or a
* tel: URI of an explicit phone number.
* <p>Output: nothing.
* @hide
*/
public static final String ACTION_CALL_EMERGENCY = "android.intent.action.CALL_EMERGENCY";
/**
* Activity action: Perform a call to any number (emergency or not)
* specified by the data.
* <p>Input: {@link #getData} is URI of a phone number to be dialed or a
* tel: URI of an explicit phone number.
* <p>Output: nothing.
* @hide
*/
public static final String ACTION_CALL_PRIVILEGED = "android.intent.action.CALL_PRIVILEGED";
/**
* Activity Action: Send a message to someone specified by the data.
* <p>Input: {@link #getData} is URI describing the target.
* <p>Output: nothing.
*/
public static final String ACTION_SENDTO = "android.intent.action.SENDTO";
/**
* Activity Action: Deliver some data to someone else. Who the data is
* being delivered to is not specified; it is up to the receiver of this
* action to ask the user where the data should be sent.
* <p>
* When launching a SEND intent, you should usually wrap it in a chooser
* (through {@link #createChooser}), which will give the proper interface
* for the user to pick how to send your data and allow you to specify
* a prompt indicating what they are doing.
* <p>
* Input: {@link #getType} is the MIME type of the data being sent.
* get*Extra can have either a {@link #EXTRA_TEXT}
* or {@link #EXTRA_STREAM} field, containing the data to be sent. If
* using EXTRA_TEXT, the MIME type should be "text/plain"; otherwise it
* should be the MIME type of the data in EXTRA_STREAM. Use {@literal *}/*
* if the MIME type is unknown (this will only allow senders that can
* handle generic data streams).
* <p>
* Optional standard extras, which may be interpreted by some recipients as
* appropriate, are: {@link #EXTRA_EMAIL}, {@link #EXTRA_CC},
* {@link #EXTRA_BCC}, {@link #EXTRA_SUBJECT}.
* <p>
* Output: nothing.
*/
public static final String ACTION_SEND = "android.intent.action.SEND";
/**
* Activity Action: Deliver multiple data to someone else.
* <p>
* Like ACTION_SEND, except the data is multiple.
* <p>
* Input: {@link #getType} is the MIME type of the data being sent.
* get*ArrayListExtra can have either a {@link #EXTRA_TEXT} or {@link
* #EXTRA_STREAM} field, containing the data to be sent.
* <p>
* Multiple types are supported, and receivers should handle mixed types
* whenever possible. The right way for the receiver to check them is to
* use the content resolver on each URI. The intent sender should try to
* put the most concrete mime type in the intent type, but it can fall
* back to {@literal <type>/*} or {@literal *}/* as needed.
* <p>
* e.g. if you are sending image/jpg and image/jpg, the intent's type can
* be image/jpg, but if you are sending image/jpg and image/png, then the
* intent's type should be image/*.
* <p>
* Optional standard extras, which may be interpreted by some recipients as
* appropriate, are: {@link #EXTRA_EMAIL}, {@link #EXTRA_CC},
* {@link #EXTRA_BCC}, {@link #EXTRA_SUBJECT}.
* <p>
* Output: nothing.
*/
public static final String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
/**
* Activity Action: Handle an incoming phone call.
* <p>Input: nothing.
* <p>Output: nothing.
*/
public static final String ACTION_ANSWER = "android.intent.action.ANSWER";
/**
* Activity Action: Insert an empty item into the given container.
* <p>Input: {@link #getData} is URI of the directory (vnd.android.cursor.dir/*)
* in which to place the data.
* <p>Output: URI of the new data that was created.
*/
public static final String ACTION_INSERT = "android.intent.action.INSERT";
/**
* Activity Action: Create a new item in the given container, initializing it
* from the current contents of the clipboard.
* <p>Input: {@link #getData} is URI of the directory (vnd.android.cursor.dir/*)
* in which to place the data.
* <p>Output: URI of the new data that was created.
*/
public static final String ACTION_PASTE = "android.intent.action.PASTE";
/**
* Activity Action: Delete the given data from its container.
* <p>Input: {@link #getData} is URI of data to be deleted.
* <p>Output: nothing.
*/
public static final String ACTION_DELETE = "android.intent.action.DELETE";
/**
* Activity Action: Run the data, whatever that means.
* <p>Input: ? (Note: this is currently specific to the test harness.)
* <p>Output: nothing.
*/
public static final String ACTION_RUN = "android.intent.action.RUN";
/**
* Activity Action: Perform a data synchronization.
* <p>Input: ?
* <p>Output: ?
*/
public static final String ACTION_SYNC = "android.intent.action.SYNC";
/**
* Activity Action: Pick an activity given an intent, returning the class
* selected.
* <p>Input: get*Extra field {@link #EXTRA_INTENT} is an Intent
* used with {@link PackageManager#queryIntentActivities} to determine the
* set of activities from which to pick.
* <p>Output: Class name of the activity that was selected.
*/
public static final String ACTION_PICK_ACTIVITY = "android.intent.action.PICK_ACTIVITY";
/**
* Activity Action: Perform a search.
* <p>Input: {@link android.app.SearchManager#QUERY getStringExtra(SearchManager.QUERY)}
* is the text to search for. If empty, simply
* enter your search results Activity with the search UI activated.
* <p>Output: nothing.
*/
public static final String ACTION_SEARCH = "android.intent.action.SEARCH";
/**
* Activity Action: Start the platform-defined tutorial
* <p>Input: {@link android.app.SearchManager#QUERY getStringExtra(SearchManager.QUERY)}
* is the text to search for. If empty, simply
* enter your search results Activity with the search UI activated.
* <p>Output: nothing.
*/
public static final String ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL";
/**
* Activity Action: Perform a web search.
* <p>
* Input: {@link android.app.SearchManager#QUERY
* getStringExtra(SearchManager.QUERY)} is the text to search for. If it is
* a url starts with http or https, the site will be opened. If it is plain
* text, Google search will be applied.
* <p>
* Output: nothing.
*/
public static final String ACTION_WEB_SEARCH = "android.intent.action.WEB_SEARCH";
/**
* Activity Action: List all available applications
* <p>Input: Nothing.
* <p>Output: nothing.
*/
public static final String ACTION_ALL_APPS = "android.intent.action.ALL_APPS";
/**
* Activity Action: Show settings for choosing wallpaper
* <p>Input: Nothing.
* <p>Output: Nothing.
*/
public static final String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
/**
* Activity Action: Show activity for reporting a bug.
* <p>Input: Nothing.
* <p>Output: Nothing.
*/
public static final String ACTION_BUG_REPORT = "android.intent.action.BUG_REPORT";
/**
* Activity Action: Main entry point for factory tests. Only used when
* the device is booting in factory test node. The implementing package
* must be installed in the system image.
* <p>Input: nothing
* <p>Output: nothing
*/
public static final String ACTION_FACTORY_TEST = "android.intent.action.FACTORY_TEST";
/**
* Activity Action: The user pressed the "call" button to go to the dialer
* or other appropriate UI for placing a call.
* <p>Input: Nothing.
* <p>Output: Nothing.
*/
public static final String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
/**
* Activity Action: Start Voice Command.
* <p>Input: Nothing.
* <p>Output: Nothing.
*/
public static final String ACTION_VOICE_COMMAND = "android.intent.action.VOICE_COMMAND";
/**
* Activity Action: Start action associated with long pressing on the
* search key.
* <p>Input: Nothing.
* <p>Output: Nothing.
*/
public static final String ACTION_SEARCH_LONG_PRESS = "android.intent.action.SEARCH_LONG_PRESS";
/**
* Activity Action: The user pressed the "Report" button in the crash/ANR dialog.
* This intent is delivered to the package which installed the application, usually
* Google Play.
* <p>Input: No data is specified. The bug report is passed in using
* an {@link #EXTRA_BUG_REPORT} field.
* <p>Output: Nothing.
*
* @see #EXTRA_BUG_REPORT
*/
public static final String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
/**
* Activity Action: Show power usage information to the user.
* <p>Input: Nothing.
* <p>Output: Nothing.
*/
public static final String ACTION_POWER_USAGE_SUMMARY = "android.intent.action.POWER_USAGE_SUMMARY";
/**
* Activity Action: Setup wizard to launch after a platform update. This
* activity should have a string meta-data field associated with it,
* {@link #METADATA_SETUP_VERSION}, which defines the current version of
* the platform for setup. The activity will be launched only if
* {@link android.provider.Settings.Secure#LAST_SETUP_SHOWN} is not the
* same value.
* <p>Input: Nothing.
* <p>Output: Nothing.
* @hide
*/
public static final String ACTION_UPGRADE_SETUP = "android.intent.action.UPGRADE_SETUP";
/**
* Activity Action: Show settings for managing network data usage of a
* specific application. Applications should define an activity that offers
* options to control data usage.
*/
public static final String ACTION_MANAGE_NETWORK_USAGE =
"android.intent.action.MANAGE_NETWORK_USAGE";
/**
* Activity Action: Launch application installer.
* <p>
* Input: The data must be a content: or file: URI at which the application
* can be retrieved. You can optionally supply
* {@link #EXTRA_INSTALLER_PACKAGE_NAME}, {@link #EXTRA_NOT_UNKNOWN_SOURCE},
* {@link #EXTRA_ALLOW_REPLACE}, and {@link #EXTRA_RETURN_RESULT}.
* <p>
* Output: If {@link #EXTRA_RETURN_RESULT}, returns whether the install
* succeeded.
*
* @see #EXTRA_INSTALLER_PACKAGE_NAME
* @see #EXTRA_NOT_UNKNOWN_SOURCE
* @see #EXTRA_RETURN_RESULT
*/
public static final String ACTION_INSTALL_PACKAGE = "android.intent.action.INSTALL_PACKAGE";
/**
* Used as a boolean extra field with {@link #ACTION_INSTALL_PACKAGE} to install a
* package. Tells the installer UI to skip the confirmation with the user
* if the .apk is replacing an existing one.
*/
public static final String EXTRA_ALLOW_REPLACE
= "android.intent.extra.ALLOW_REPLACE";
/**
* Extra used to indicate that an intent can allow the user to select and return multiple items.
* This is a boolean extra; the default is false. If true, an implementation is allowed to present
* the user with a UI where they can pick multiple items that are all returned to the caller.
* When this happens, they should be returned as the getClipData() part of the result Intent.
*/
public static final String EXTRA_ALLOW_MULTIPLE
= "android.intent.extra.ALLOW_MULTIPLE";
/**
* Used to indicate that a GET_CONTENT intent only wants URIs that can be opened with
* ContentResolver.openInputStream. Openable URIs must support the columns in OpenableColumns
* when queried, though it is allowable for those columns to be blank.
*/
public static final String CATEGORY_OPENABLE = "android.intent.category.OPENABLE";
/** /**
* Create an empty intent. * Create an empty intent.
*/ */
@@ -1407,6 +1912,35 @@ public class Intent implements Parcelable, Cloneable {
return null; return null;
} }
/**
* Set an explicit MIME data type.
*
* <p>This is used to create intents that only specify a type and not data,
* for example to indicate the type of data to return.
*
* <p>This method automatically clears any data that was
* previously set (for example by {@link #setData}).
*
* <p><em>Note: MIME type matching in the Android framework is
* case-sensitive, unlike formal RFC MIME types. As a result,
* you should always write your MIME types with lower case letters,
* or use {@link #normalizeMimeType} or {@link #setTypeAndNormalize}
* to ensure that it is converted to lower case.</em>
*
* @param type The MIME type of the data being handled by this intent.
*
* @return Returns the same Intent object, for chaining multiple calls
* into a single statement.
*
* @see #getType
* @see #setTypeAndNormalize
* @see #setDataAndType
* @see #normalizeMimeType
*/
public Intent setType(String type) {
return null;
}
/** /**
* Add extended data to the intent. The name must include a package prefix, for * Add extended data to the intent. The name must include a package prefix, for
* example the app com.android.contacts would use names like * example the app com.android.contacts would use names like
@@ -2071,4 +2605,23 @@ public class Intent implements Parcelable, Cloneable {
return null; return null;
} }
/**
* Add a new category to the intent. Categories provide additional detail
* about the action the intent performs. When resolving an intent, only
* activities that provide <em>all</em> of the requested categories will be
* used.
*
* @param category The desired category. This can be either one of the
* predefined Intent categories, or a custom category in your own
* namespace.
*
* @return Returns the same Intent object, for chaining multiple calls
* into a single statement.
*
* @see #hasCategory
* @see #removeCategory
*/
public Intent addCategory(String category) {
return null;
}
} }

View File

@@ -0,0 +1,406 @@
/*
* Copyright (C) 2008 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.os;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
/**
* <p>AsyncTask enables proper and easy use of the UI thread. This class allows you
* to perform background operations and publish results on the UI thread without
* having to manipulate threads and/or handlers.</p>
*
* <p>AsyncTask is designed to be a helper class around {@link Thread} and {@link Handler}
* and does not constitute a generic threading framework. AsyncTasks should ideally be
* used for short operations (a few seconds at the most.) If you need to keep threads
* running for long periods of time, it is highly recommended you use the various APIs
* provided by the <code>java.util.concurrent</code> package such as {@link Executor},
* {@link ThreadPoolExecutor} and {@link FutureTask}.</p>
*
* <p>An asynchronous task is defined by a computation that runs on a background thread and
* whose result is published on the UI thread. An asynchronous task is defined by 3 generic
* types, called <code>Params</code>, <code>Progress</code> and <code>Result</code>,
* and 4 steps, called <code>onPreExecute</code>, <code>doInBackground</code>,
* <code>onProgressUpdate</code> and <code>onPostExecute</code>.</p>
*
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For more information about using tasks and threads, read the
* <a href="{@docRoot}guide/components/processes-and-threads.html">Processes and
* Threads</a> developer guide.</p>
* </div>
*
* <h2>Usage</h2>
* <p>AsyncTask must be subclassed to be used. The subclass will override at least
* one method ({@link #doInBackground}), and most often will override a
* second one ({@link #onPostExecute}.)</p>
*
* <p>Here is an example of subclassing:</p>
* <pre class="prettyprint">
* private class DownloadFilesTask extends AsyncTask&lt;URL, Integer, Long&gt; {
* protected Long doInBackground(URL... urls) {
* int count = urls.length;
* long totalSize = 0;
* for (int i = 0; i < count; i++) {
* totalSize += Downloader.downloadFile(urls[i]);
* publishProgress((int) ((i / (float) count) * 100));
* // Escape early if cancel() is called
* if (isCancelled()) break;
* }
* return totalSize;
* }
*
* protected void onProgressUpdate(Integer... progress) {
* setProgressPercent(progress[0]);
* }
*
* protected void onPostExecute(Long result) {
* showDialog("Downloaded " + result + " bytes");
* }
* }
* </pre>
*
* <p>Once created, a task is executed very simply:</p>
* <pre class="prettyprint">
* new DownloadFilesTask().execute(url1, url2, url3);
* </pre>
*
* <h2>AsyncTask's generic types</h2>
* <p>The three types used by an asynchronous task are the following:</p>
* <ol>
* <li><code>Params</code>, the type of the parameters sent to the task upon
* execution.</li>
* <li><code>Progress</code>, the type of the progress units published during
* the background computation.</li>
* <li><code>Result</code>, the type of the result of the background
* computation.</li>
* </ol>
* <p>Not all types are always used by an asynchronous task. To mark a type as unused,
* simply use the type {@link Void}:</p>
* <pre>
* private class MyTask extends AsyncTask&lt;Void, Void, Void&gt; { ... }
* </pre>
*
* <h2>The 4 steps</h2>
* <p>When an asynchronous task is executed, the task goes through 4 steps:</p>
* <ol>
* <li>{@link #onPreExecute()}, invoked on the UI thread before the task
* is executed. This step is normally used to setup the task, for instance by
* showing a progress bar in the user interface.</li>
* <li>{@link #doInBackground}, invoked on the background thread
* immediately after {@link #onPreExecute()} finishes executing. This step is used
* to perform background computation that can take a long time. The parameters
* of the asynchronous task are passed to this step. The result of the computation must
* be returned by this step and will be passed back to the last step. This step
* can also use {@link #publishProgress} to publish one or more units
* of progress. These values are published on the UI thread, in the
* {@link #onProgressUpdate} step.</li>
* <li>{@link #onProgressUpdate}, invoked on the UI thread after a
* call to {@link #publishProgress}. The timing of the execution is
* undefined. This method is used to display any form of progress in the user
* interface while the background computation is still executing. For instance,
* it can be used to animate a progress bar or show logs in a text field.</li>
* <li>{@link #onPostExecute}, invoked on the UI thread after the background
* computation finishes. The result of the background computation is passed to
* this step as a parameter.</li>
* </ol>
*
* <h2>Cancelling a task</h2>
* <p>A task can be cancelled at any time by invoking {@link #cancel(boolean)}. Invoking
* this method will cause subsequent calls to {@link #isCancelled()} to return true.
* After invoking this method, {@link #onCancelled(Object)}, instead of
* {@link #onPostExecute(Object)} will be invoked after {@link #doInBackground(Object[])}
* returns. To ensure that a task is cancelled as quickly as possible, you should always
* check the return value of {@link #isCancelled()} periodically from
* {@link #doInBackground(Object[])}, if possible (inside a loop for instance.)</p>
*
* <h2>Threading rules</h2>
* <p>There are a few threading rules that must be followed for this class to
* work properly:</p>
* <ul>
* <li>The AsyncTask class must be loaded on the UI thread. This is done
* automatically as of {@link android.os.Build.VERSION_CODES#JELLY_BEAN}.</li>
* <li>The task instance must be created on the UI thread.</li>
* <li>{@link #execute} must be invoked on the UI thread.</li>
* <li>Do not call {@link #onPreExecute()}, {@link #onPostExecute},
* {@link #doInBackground}, {@link #onProgressUpdate} manually.</li>
* <li>The task can be executed only once (an exception will be thrown if
* a second execution is attempted.)</li>
* </ul>
*
* <h2>Memory observability</h2>
* <p>AsyncTask guarantees that all callback calls are synchronized in such a way that the following
* operations are safe without explicit synchronizations.</p>
* <ul>
* <li>Set member fields in the constructor or {@link #onPreExecute}, and refer to them
* in {@link #doInBackground}.
* <li>Set member fields in {@link #doInBackground}, and refer to them in
* {@link #onProgressUpdate} and {@link #onPostExecute}.
* </ul>
*
* <h2>Order of execution</h2>
* <p>When first introduced, AsyncTasks were executed serially on a single background
* thread. Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
* to a pool of threads allowing multiple tasks to operate in parallel. Starting with
* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are executed on a single
* thread to avoid common application errors caused by parallel execution.</p>
* <p>If you truly want parallel execution, you can invoke
* {@link #executeOnExecutor(java.util.concurrent.Executor, Object[])} with
* {@link #THREAD_POOL_EXECUTOR}.</p>
*/
public abstract class AsyncTask<Params, Progress, Result> {
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
}
/**
* Override this method to perform a computation on a background thread. The
* specified parameters are the parameters passed to {@link #execute}
* by the caller of this task.
*
* This method can call {@link #publishProgress} to publish updates
* on the UI thread.
*
* @param params The parameters of the task.
*
* @return A result, defined by the subclass of this task.
*
* @see #onPreExecute()
* @see #onPostExecute
* @see #publishProgress
*/
protected abstract Result doInBackground(Params... params);
/**
* Runs on the UI thread before {@link #doInBackground}.
*
* @see #onPostExecute
* @see #doInBackground
*/
protected void onPreExecute() {
}
/**
* <p>Runs on the UI thread after {@link #doInBackground}. The
* specified result is the value returned by {@link #doInBackground}.</p>
*
* <p>This method won't be invoked if the task was cancelled.</p>
*
* @param result The result of the operation computed by {@link #doInBackground}.
*
* @see #onPreExecute
* @see #doInBackground
* @see #onCancelled(Object)
*/
protected void onPostExecute(Result result) {
}
/**
* Runs on the UI thread after {@link #publishProgress} is invoked.
* The specified values are the values passed to {@link #publishProgress}.
*
* @param values The values indicating progress.
*
* @see #publishProgress
* @see #doInBackground
*/
protected void onProgressUpdate(Progress... values) {
}
/**
* <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
* {@link #doInBackground(Object[])} has finished.</p>
*
* <p>The default implementation simply invokes {@link #onCancelled()} and
* ignores the result. If you write your own implementation, do not call
* <code>super.onCancelled(result)</code>.</p>
*
* @param result The result, if any, computed in
* {@link #doInBackground(Object[])}, can be null
*
* @see #cancel(boolean)
* @see #isCancelled()
*/
protected void onCancelled(Result result) {
onCancelled();
}
/**
* <p>Applications should preferably override {@link #onCancelled(Object)}.
* This method is invoked by the default implementation of
* {@link #onCancelled(Object)}.</p>
*
* <p>Runs on the UI thread after {@link #cancel(boolean)} is invoked and
* {@link #doInBackground(Object[])} has finished.</p>
*
* @see #onCancelled(Object)
* @see #cancel(boolean)
* @see #isCancelled()
*/
protected void onCancelled() {
}
/**
* Returns <tt>true</tt> if this task was cancelled before it completed
* normally. If you are calling {@link #cancel(boolean)} on the task,
* the value returned by this method should be checked periodically from
* {@link #doInBackground(Object[])} to end the task as soon as possible.
*
* @return <tt>true</tt> if task was cancelled before it completed
*
* @see #cancel(boolean)
*/
public final boolean isCancelled() {
return false;
}
/**
* <p>Attempts to cancel execution of this task. This attempt will
* fail if the task has already completed, already been cancelled,
* or could not be cancelled for some other reason. If successful,
* and this task has not started when <tt>cancel</tt> is called,
* this task should never run. If the task has already started,
* then the <tt>mayInterruptIfRunning</tt> parameter determines
* whether the thread executing this task should be interrupted in
* an attempt to stop the task.</p>
*
* <p>Calling this method will result in {@link #onCancelled(Object)} being
* invoked on the UI thread after {@link #doInBackground(Object[])}
* returns. Calling this method guarantees that {@link #onPostExecute(Object)}
* is never invoked. After invoking this method, you should check the
* value returned by {@link #isCancelled()} periodically from
* {@link #doInBackground(Object[])} to finish the task as early as
* possible.</p>
*
* @param mayInterruptIfRunning <tt>true</tt> if the thread executing this
* task should be interrupted; otherwise, in-progress tasks are allowed
* to complete.
*
* @return <tt>false</tt> if the task could not be cancelled,
* typically because it has already completed normally;
* <tt>true</tt> otherwise
*
* @see #isCancelled()
* @see #onCancelled(Object)
*/
public final boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
/**
* Waits if necessary for the computation to complete, and then
* retrieves its result.
*
* @return The computed result.
*
* @throws CancellationException If the computation was cancelled.
* @throws ExecutionException If the computation threw an exception.
* @throws InterruptedException If the current thread was interrupted
* while waiting.
*/
public final Result get() throws InterruptedException, ExecutionException {
return null;
}
/**
* Executes the task with the specified parameters. The task returns
* itself (this) so that the caller can keep a reference to it.
*
* <p>Note: this function schedules the task on a queue for a single background
* thread or pool of threads depending on the platform version. When first
* introduced, AsyncTasks were executed serially on a single background thread.
* Starting with {@link android.os.Build.VERSION_CODES#DONUT}, this was changed
* to a pool of threads allowing multiple tasks to operate in parallel. Starting
* {@link android.os.Build.VERSION_CODES#HONEYCOMB}, tasks are back to being
* executed on a single thread to avoid common application errors caused
* by parallel execution. If you truly want parallel execution, you can use
* the {@link #executeOnExecutor} version of this method
* with {@link #THREAD_POOL_EXECUTOR}; however, see commentary there for warnings
* on its use.
*
* <p>This method must be invoked on the UI thread.
*
* @param params The parameters of the task.
*
* @return This instance of AsyncTask.
*
* @throws IllegalStateException If {@link #getStatus()} returns either
* {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
*
* @see #executeOnExecutor(java.util.concurrent.Executor, Object[])
* @see #execute(Runnable)
*/
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return null;
}
/**
* Executes the task with the specified parameters. The task returns
* itself (this) so that the caller can keep a reference to it.
*
* <p>This method is typically used with {@link #THREAD_POOL_EXECUTOR} to
* allow multiple tasks to run in parallel on a pool of threads managed by
* AsyncTask, however you can also use your own {@link Executor} for custom
* behavior.
*
* <p><em>Warning:</em> Allowing multiple tasks to run in parallel from
* a thread pool is generally <em>not</em> what one wants, because the order
* of their operation is not defined. For example, if these tasks are used
* to modify any state in common (such as writing a file due to a button click),
* there are no guarantees on the order of the modifications.
* Without careful work it is possible in rare cases for the newer version
* of the data to be over-written by an older one, leading to obscure data
* loss and stability issues. Such changes are best
* executed in serial; to guarantee such work is serialized regardless of
* platform version you can use this function with {@link #SERIAL_EXECUTOR}.
*
* <p>This method must be invoked on the UI thread.
*
* @param exec The executor to use. {@link #THREAD_POOL_EXECUTOR} is available as a
* convenient process-wide thread pool for tasks that are loosely coupled.
* @param params The parameters of the task.
*
* @return This instance of AsyncTask.
*
* @throws IllegalStateException If {@link #getStatus()} returns either
* {@link AsyncTask.Status#RUNNING} or {@link AsyncTask.Status#FINISHED}.
*
* @see #execute(Object[])
*/
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
return null;
}
/**
* This method can be invoked from {@link #doInBackground} to
* publish updates on the UI thread while the background computation is
* still running. Each call to this method will trigger the execution of
* {@link #onProgressUpdate} on the UI thread.
*
* {@link #onProgressUpdate} will not be called if the task has been
* canceled.
*
* @param values The progress values to update the UI with.
*
* @see #onProgressUpdate
* @see #doInBackground
*/
protected final void publishProgress(Progress... values) {
}
}