android support! thanks to TachiWeb devs.

This commit is contained in:
Aria Moradi 2021-01-02 04:57:20 +03:30
parent ced07d4e1e
commit 1e46a0c78c
291 changed files with 68699 additions and 16 deletions

View File

@ -0,0 +1,4 @@
dependencies {
// Config API
// implementation("com.typesafe:config:1.4.0")
}

View File

@ -0,0 +1,12 @@
package xyz.nulldev.ts.config
import org.kodein.di.DI
import org.kodein.di.bind
import org.kodein.di.singleton
class ConfigKodeinModule {
fun create() = DI.Module("ConfigManager") {
//Config module
bind<ConfigManager>() with singleton { GlobalConfigManager }
}
}

View File

@ -0,0 +1,74 @@
package xyz.nulldev.ts.config
import com.typesafe.config.Config
import com.typesafe.config.ConfigFactory
import com.typesafe.config.ConfigRenderOptions
import mu.KotlinLogging
import java.io.File
/**
* Manages app config.
*/
open class ConfigManager {
private val generatedModules
= mutableMapOf<Class<out ConfigModule>, ConfigModule>()
val config by lazy { loadConfigs() }
//Public read-only view of modules
val loadedModules: Map<Class<out ConfigModule>, ConfigModule>
get() = generatedModules
open val configFolder: String
get() = System.getProperty("compat-configdirs") ?: "tachiserver-data/config"
val logger = KotlinLogging.logger {}
/**
* Get a config module
*/
inline fun <reified T : ConfigModule> module(): T
= loadedModules[T::class.java] as T
/**
* Get a config module (Java API)
*/
fun <T : ConfigModule> module(type: Class<T>): T
= loadedModules[type] as T
/**
* Load configs
*/
fun loadConfigs(): Config {
val configs = mutableListOf<Config>()
//Load reference config
configs += ConfigFactory.parseResources("reference.conf")
//Load custom configs from dir
File(configFolder).listFiles()?.map {
ConfigFactory.parseFile(it)
}?.filterNotNull()?.forEach {
configs += it.withFallback(configs.last())
}
val config = configs.last().resolve()
logger.debug {
"Loaded config:\n" + config.root().render(ConfigRenderOptions.concise().setFormatted(true))
}
return config
}
fun registerModule(module: ConfigModule) {
generatedModules.put(module.javaClass, module)
}
fun registerModules(vararg modules: ConfigModule) {
modules.forEach {
registerModule(it)
}
}
}
object GlobalConfigManager : ConfigManager()

View File

@ -0,0 +1,8 @@
package xyz.nulldev.ts.config
import com.typesafe.config.Config
/**
* Abstract config module.
*/
abstract class ConfigModule(config: Config)

View File

@ -0,0 +1,35 @@
package xyz.nulldev.ts.config
import com.typesafe.config.Config
import java.io.File
class ServerConfig(config: Config) : ConfigModule(config) {
val ip = config.getString("ip")
val port = config.getInt("port")
val allowConfigChanges = config.getBoolean("allowConfigChanges")
val enableWebUi = config.getBoolean("enableWebUi")
val useOldWebUi = config.getBoolean("useOldWebUi")
val prettyPrintApi = config.getBoolean("prettyPrintApi")
// TODO Apply to operation IDs
val disabledApiEndpoints = config.getStringList("disabledApiEndpoints").map(String::toLowerCase)
val enabledApiEndpoints = config.getStringList("enabledApiEndpoints").map(String::toLowerCase)
val httpInitializedPrintMessage = config.getString("httpInitializedPrintMessage")
val useExternalStaticFiles = config.getBoolean("useExternalStaticFiles")
val externalStaticFilesFolder = config.getString("externalStaticFilesFolder")
val rootDir = registerFile(config.getString("rootDir"))
val patchesDir = registerFile(config.getString("patchesDir"))
fun registerFile(file: String): File {
return File(file).apply {
mkdirs()
}
}
companion object {
fun register(config: Config)
= ServerConfig(config.getConfig("ts.server"))
}
}

View File

@ -0,0 +1,6 @@
package xyz.nulldev.ts.config.util
import com.typesafe.config.Config
operator fun Config.get(key: String) = getString(key)
?: throw IllegalStateException("Could not find value for config entry: $key!")

View File

@ -0,0 +1 @@
xyz.nulldev.ts.api.v2.java.impl.ServerAPIImpl

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,22 @@
[
{
"label": "Sync",
"icon": "import_export",
"type": "nested",
"prefs": []
},
{
"label": "Server",
"icon": "dns",
"type": "nested",
"prefs": [
{
"label": "Password authentication",
"type": "text-password",
"default": "",
"key": "pref_ts_server_password",
"hint": "Enter a password"
}
]
}
]

View File

@ -0,0 +1,87 @@
# Server ip and port bindings
ts.server.ip = 0.0.0.0
ts.server.port = 4567
# Allow/disallow preference changes (useful for demos)
ts.server.allowConfigChanges = true
# Enable the WebUI? Note: The API and multi-user sync server ui will remain available even if the WebUI is disabled
ts.server.enableWebUi = true
# 'true' to use the old, buggy/memory-leaking WebUI
ts.server.useOldWebUi = false
# 'true' to pretty print all JSON API responses
ts.server.prettyPrintApi = false
# List of blacklisted/whitelisted API endpoints/operation IDs
ts.server.disabledApiEndpoints = []
ts.server.enabledApiEndpoints = []
# Message to print in the console when the API has finished booting
ts.server.httpInitializedPrintMessage = ""
# Use external folder for static files
ts.server.useExternalStaticFiles = false
ts.server.externalStaticFilesFolder = ""
# Root storage dir
ts.server.rootDir = tachiserver-data
# Dir to store JVM patches
ts.server.patchesDir = ${ts.server.rootDir}/patches
# Storage dir for the emulated Android app
android.files.rootDir = ${ts.server.rootDir}/android-compat/appdata
# External storage dir for the emulated Android app's
android.files.externalStorageDir = ${ts.server.rootDir}/android-compat/extappdata
# Internal Android directories
android.files.dataDir = ${android.files.rootDir}/data
android.files.filesDir = ${android.files.rootDir}/files
android.files.cacheDir = ${android.files.rootDir}/cache
android.files.codeCacheDir = ${android.files.rootDir}/code_cache
android.files.noBackupFilesDir = ${android.files.rootDir}/no_backup
android.files.databasesDir = ${android.files.rootDir}/databases
android.files.prefsDir = ${android.files.rootDir}/shared_prefs
# External Android directories
android.files.externalFilesDirs = [${android.files.externalStorageDir}/files]
android.files.obbDirs = [${android.files.externalStorageDir}/obb]
android.files.externalCacheDirs = [${android.files.externalStorageDir}/cache]
android.files.externalMediaDirs = [${android.files.externalStorageDir}/media]
android.files.downloadCacheDir = ${android.files.externalStorageDir}/downloadCache
android.files.packageDir = ${ts.server.rootDir}/android-compat/packages
# Emulated Android app package name
android.app.packageName = eu.kanade.tachiyomi
# Debug mode for the emulated Android app
android.app.debug = true
# Whether or not the emulated Android system is debuggable
android.system.isDebuggable = true
# Is the multi-user sync server enabled? Does not affect the single-user sync server included in the API.
ts.syncd.enable = false
# The URL of this server (displayed in the sync server web ui)
ts.syncd.baseUrl = "http://example.com"
# 'true' to disable the API and only enable the multi-user sync server
ts.syncd.syncOnlyMode = false
# The root directory to store synchronized data
ts.syncd.rootDir = ${ts.server.rootDir}/sync/accounts
# Location to store config files for the sandbox
ts.syncd.sandboxedConfig = ${ts.server.rootDir}/sync/sandboxed_config.config
# Recaptcha stuff for signup/login
ts.syncd.recaptcha.siteKey = ""
ts.syncd.recaptcha.secret = ""
# Sync server display name
ts.syncd.name = "Tachiyomi sync server"
# Header used to forward the IP to the multi-user sync server if the server is behind a reverse proxy
ts.syncd.ipHeader = ""

View File

@ -0,0 +1,72 @@
plugins {
application
}
repositories {
mavenCentral()
jcenter()
maven {
url = uri("https://jitpack.io")
}
maven {
url = uri("https://maven.google.com")
}
}
dependencies {
// Android stub library
// compileOnly( fileTree(File(rootProject.rootDir, "libs/android"), include: "*.jar")
implementation(fileTree("lib/"))
implementation(fileTree("${rootProject.rootDir}/server/lib/dex2jar/"))
// Android JAR libs
// compileOnly( fileTree(dir: new File(rootProject.rootDir, "libs/other"), include: "*.jar")
// JSON
compileOnly( "com.google.code.gson:gson:2.8.6")
// Javassist
compileOnly( "org.javassist:javassist:3.27.0-GA")
// Coroutines
val kotlinx_coroutines_version = "1.4.2"
compileOnly( "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinx_coroutines_version")
compileOnly( "org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:$kotlinx_coroutines_version")
// XML
compileOnly( group= "xmlpull", name= "xmlpull", version= "1.1.3.1")
// Config API
implementation( project(":AndroidCompat:Config"))
// dex2jar
// compileOnly( "dex2jar:dex-translator")
// APK parser
compileOnly("net.dongliu:apk-parser:2.6.10")
// APK sig verifier
compileOnly("com.android.tools.build:apksig:4.2.0-alpha13")
// AndroidX annotations
compileOnly( "androidx.annotation:annotation:1.2.0-alpha01")
// compileOnly("io.reactivex:rxjava:1.3.8")
}
//def fatJarTask = tasks.getByPath(':AndroidCompat:JVMPatch:fatJar')
//
//// Copy JVM core patches
//task copyJVMPatches(type: Copy) {
// from fatJarTask.outputs.files
// into 'src/main/resources/patches'
//}
//
//compileOnly(Java.dependsOn gradle.includedBuild('dex2jar').task(':dex-translator:assemble')
//compileOnly(Java.dependsOn copyJVMPatches
//copyJVMPatches.dependsOn fatJarTask
//

1
AndroidCompat/lib/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
android.jar

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be an anim resource reference (e.g. {@link android.R.anim#fade_in}).
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface AnimRes {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be an animator resource reference (e.g. {@link android.R.animator#fade_in}).
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface AnimatorRes {
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be a resource reference of any type. If the specific type is known, use
* one of the more specific annotations instead, such as {@link StringRes} or
* {@link DrawableRes}.
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface AnyRes {
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2016 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that the annotated element is a multi-user application ID. This is
* <em>not</em> the same as a UID.
*
* @hide
*/
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface AppIdInt {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be an array resource reference (e.g. {@link android.R.array#phoneTypes}).
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface ArrayRes {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be an attribute reference (e.g. {@link android.R.attr#action}).
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface AttrRes {
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2015 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that the annotated method should only be called on the binder thread.
* If the annotated element is a class, then all methods in the class should be called
* on the binder thread.
* <p>
* Example:
* <pre><code>
* &#64;BinderThread
* public BeamShareData createBeamShareData() { ... }
* </code></pre>
*
* {@hide}
*/
@Retention(SOURCE)
@Target({METHOD,CONSTRUCTOR,TYPE})
public @interface BinderThread {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be a boolean resource reference.
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface BoolRes {
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2015 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that any overriding methods should invoke this method as well.
* <p>
* Example:
* <pre><code>
* &#64;CallSuper
* public abstract void onFocusLost();
* </code></pre>
*
* @hide
*/
@Retention(SOURCE)
@Target({METHOD})
public @interface CallSuper {
}

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2015 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that the annotated method returns a result that it typically is
* an error to ignore. This is usually used for methods that have no side effect,
* so calling it without actually looking at the result usually means the developer
* has misunderstood what the method does.
* <p>
* Example:
* <pre>{@code
* public @CheckResult String trim(String s) { return s.trim(); }
* ...
* s.trim(); // this is probably an error
* s = s.trim(); // ok
* }</pre>
*
* @hide
*/
@Retention(SOURCE)
@Target({METHOD})
public @interface CheckResult {
/** Defines the name of the suggested method to use instead, if applicable (using
* the same signature format as javadoc.) If there is more than one possibility,
* list them all separated by commas.
* <p>
* For example, ProcessBuilder has a method named {@code redirectErrorStream()}
* which sounds like it might redirect the error stream. It does not. It's just
* a getter which returns whether the process builder will redirect the error stream,
* and to actually set it, you must call {@code redirectErrorStream(boolean)}.
* In that case, the method should be defined like this:
* <pre>
* &#64;CheckResult(suggest="#redirectErrorStream(boolean)")
* public boolean redirectErrorStream() { ... }
* </pre>
*/
String suggest() default "";
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2015 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that the annotated element represents a packed color
* int, {@code AARRGGBB}. If applied to an int array, every element
* in the array represents a color integer.
* <p>
* Example:
* <pre>{@code
* public abstract void setTextColor(@ColorInt int color);
* }</pre>
*
* @hide
*/
@Retention(SOURCE)
@Target({PARAMETER,METHOD,LOCAL_VARIABLE,FIELD})
public @interface ColorInt {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be a color resource reference (e.g. {@link android.R.color#black}).
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface ColorRes {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be a dimension resource reference (e.g. {@link android.R.dimen#app_icon_size}).
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface DimenRes {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be a drawable resource reference (e.g. {@link android.R.attr#alertDialogIcon}).
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface DrawableRes {
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2015 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that the annotated element should be a float or double in the given range
* <p>
* Example:
* <pre><code>
* &#64;FloatRange(from=0.0,to=1.0)
* public float getAlpha() {
* ...
* }
* </code></pre>
*
* @hide
*/
@Retention(SOURCE)
@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE})
public @interface FloatRange {
/** Smallest value. Whether it is inclusive or not is determined
* by {@link #fromInclusive} */
double from() default Double.NEGATIVE_INFINITY;
/** Largest value. Whether it is inclusive or not is determined
* by {@link #toInclusive} */
double to() default Double.POSITIVE_INFINITY;
/** Whether the from value is included in the range */
boolean fromInclusive() default true;
/** Whether the to value is included in the range */
boolean toInclusive() default true;
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be a fraction resource reference.
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface FractionRes {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be an id resource reference (e.g. {@link android.R.id#copy}).
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface IdRes {
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that the annotated element of integer type, represents
* a logical type and that its value should be one of the explicitly
* named constants. If the {@link #flag()} attribute is set to true,
* multiple constants can be combined.
* <p>
* <pre><code>
* &#64;Retention(SOURCE)
* &#64;IntDef({NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
* public @interface NavigationMode {}
* public static final int NAVIGATION_MODE_STANDARD = 0;
* public static final int NAVIGATION_MODE_LIST = 1;
* public static final int NAVIGATION_MODE_TABS = 2;
* ...
* public abstract void setNavigationMode(@NavigationMode int mode);
* &#64;NavigationMode
* public abstract int getNavigationMode();
* </code></pre>
* For a flag, set the flag attribute:
* <pre><code>
* &#64;IntDef(
* flag = true,
* value = {NAVIGATION_MODE_STANDARD, NAVIGATION_MODE_LIST, NAVIGATION_MODE_TABS})
* </code></pre>
*
* @hide
*/
@Retention(SOURCE)
@Target({ANNOTATION_TYPE})
public @interface IntDef {
/** Defines the constant prefix for this element */
String[] prefix() default "";
/** Defines the allowed constants for this element */
long[] value() default {};
/** Defines whether the constants can be used as a flag, or just as an enum (the default) */
boolean flag() default false;
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2015 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that the annotated element should be an int or long in the given range
* <p>
* Example:
* <pre><code>
* &#64;IntRange(from=0,to=255)
* public int getAlpha() {
* ...
* }
* </code></pre>
*
* @hide
*/
@Retention(SOURCE)
@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE,ANNOTATION_TYPE})
public @interface IntRange {
/** Smallest value, inclusive */
long from() default Long.MIN_VALUE;
/** Largest value, inclusive */
long to() default Long.MAX_VALUE;
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be an integer resource reference (e.g. {@link android.R.integer#config_shortAnimTime}).
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface IntegerRes {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be an interpolator resource reference (e.g. {@link android.R.interpolator#cycle}).
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface InterpolatorRes {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be a layout resource reference (e.g. {@link android.R.layout#list_content}).
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface LayoutRes {
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2015 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that the annotated method should only be called on the main thread.
* If the annotated element is a class, then all methods in the class should be called
* on the main thread.
* <p>
* Example:
* <pre><code>
* &#64;MainThread
* public void deliverResult(D data) { ... }
* </code></pre>
*
* {@hide}
*/
@Retention(SOURCE)
@Target({METHOD,CONSTRUCTOR,TYPE})
public @interface MainThread {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be a menu resource reference.
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface MenuRes {
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that a parameter, field or method return value can never be null.
* <p>
* This is a marker annotation and it has no specific attributes.
*
* @hide
*/
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface NonNull {
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that a parameter, field or method return value can be null.
* <p>
* When decorating a method call parameter, this denotes that the parameter can
* legitimately be null and the method will gracefully deal with it. Typically
* used on optional parameters.
* <p>
* When decorating a method, this denotes the method might legitimately return
* null.
* <p>
* This is a marker annotation and it has no specific attributes.
*
* @hide
*/
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface Nullable {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be a plurals resource reference.
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface PluralsRes {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be a raw resource reference.
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface RawRes {
}

View File

@ -0,0 +1,131 @@
/*
* Copyright (C) 2015 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that the annotated element requires (or may require) one or more permissions.
* <p/>
* Example of requiring a single permission:
* <pre>{@code
* {@literal @}RequiresPermission(Manifest.permission.SET_WALLPAPER)
* public abstract void setWallpaper(Bitmap bitmap) throws IOException;
*
* {@literal @}RequiresPermission(ACCESS_COARSE_LOCATION)
* public abstract Location getLastKnownLocation(String provider);
* }</pre>
* Example of requiring at least one permission from a set:
* <pre>{@code
* {@literal @}RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
* public abstract Location getLastKnownLocation(String provider);
* }</pre>
* Example of requiring multiple permissions:
* <pre>{@code
* {@literal @}RequiresPermission(allOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
* public abstract Location getLastKnownLocation(String provider);
* }</pre>
* Example of requiring separate read and write permissions for a content provider:
* <pre>{@code
* {@literal @}RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))
* {@literal @}RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))
* public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");
* }</pre>
* <p>
* When specified on a parameter, the annotation indicates that the method requires
* a permission which depends on the value of the parameter. For example, consider
* {@link android.app.Activity#startActivity(Intent)}:
* <pre>{@code
* public void startActivity(@RequiresPermission Intent intent) { ... }
* }</pre>
* Notice how there are no actual permission names listed in the annotation. The actual
* permissions required will depend on the particular intent passed in. For example,
* the code may look like this:
* <pre>{@code
* Intent intent = new Intent(Intent.ACTION_CALL);
* startActivity(intent);
* }</pre>
* and the actual permission requirement for this particular intent is described on
* the Intent name itself:
* <pre>{@code
* {@literal @}RequiresPermission(Manifest.permission.CALL_PHONE)
* public static final String ACTION_CALL = "android.intent.action.CALL";
* }</pre>
*
* @hide
*/
@Retention(SOURCE)
@Target({ANNOTATION_TYPE,METHOD,CONSTRUCTOR,FIELD,PARAMETER})
public @interface RequiresPermission {
/**
* The name of the permission that is required, if precisely one permission
* is required. If more than one permission is required, specify either
* {@link #allOf()} or {@link #anyOf()} instead.
* <p>
* If specified, {@link #anyOf()} and {@link #allOf()} must both be null.
*/
String value() default "";
/**
* Specifies a list of permission names that are all required.
* <p>
* If specified, {@link #anyOf()} and {@link #value()} must both be null.
*/
String[] allOf() default {};
/**
* Specifies a list of permission names where at least one is required
* <p>
* If specified, {@link #allOf()} and {@link #value()} must both be null.
*/
String[] anyOf() default {};
/**
* If true, the permission may not be required in all cases (e.g. it may only be
* enforced on certain platforms, or for certain call parameters, etc.
*/
boolean conditional() default false;
/**
* Specifies that the given permission is required for read operations.
* <p>
* When specified on a parameter, the annotation indicates that the method requires
* a permission which depends on the value of the parameter (and typically
* the corresponding field passed in will be one of a set of constants which have
* been annotated with a <code>@RequiresPermission</code> annotation.)
*/
@Target({FIELD, METHOD, PARAMETER})
@interface Read {
RequiresPermission value() default @RequiresPermission;
}
/**
* Specifies that the given permission is required for write operations.
* <p>
* When specified on a parameter, the annotation indicates that the method requires
* a permission which depends on the value of the parameter (and typically
* the corresponding field passed in will be one of a set of constants which have
* been annotated with a <code>@RequiresPermission</code> annotation.)
*/
@Target({FIELD, METHOD, PARAMETER})
@interface Write {
RequiresPermission value() default @RequiresPermission;
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Indicates a constant field value should be exported to be used in the SDK tools.
* @hide
*/
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.SOURCE)
public @interface SdkConstant {
public static enum SdkConstantType {
ACTIVITY_INTENT_ACTION, BROADCAST_INTENT_ACTION, SERVICE_ACTION, INTENT_CATEGORY, FEATURE;
}
SdkConstantType value();
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2015 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that the annotated element should have a given size or length.
* Note that "-1" means "unset". Typically used with a parameter or
* return value of type array or collection.
* <p>
* Example:
* <pre>{@code
* public void getLocationInWindow(@Size(2) int[] location) {
* ...
* }
* }</pre>
*
* @hide
*/
@Retention(SOURCE)
@Target({PARAMETER,LOCAL_VARIABLE,METHOD,FIELD})
public @interface Size {
/** An exact size (or -1 if not specified) */
long value() default -1;
/** A minimum size, inclusive */
long min() default Long.MIN_VALUE;
/** A maximum size, inclusive */
long max() default Long.MAX_VALUE;
/** The size must be a multiple of this factor */
long multiple() default 1;
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.RetentionPolicy.CLASS;
/**
* Denotes that the annotated String element, represents a logical
* type and that its value should be one of the explicitly named constants.
* <p>
* Example:
* <pre><code>
* &#64;Retention(SOURCE)
* &#64;StringDef({
* POWER_SERVICE,
* WINDOW_SERVICE,
* LAYOUT_INFLATER_SERVICE
* })
* public @interface ServiceName {}
* public static final String POWER_SERVICE = "power";
* public static final String WINDOW_SERVICE = "window";
* public static final String LAYOUT_INFLATER_SERVICE = "layout_inflater";
* ...
* public abstract Object getSystemService(@ServiceName String name);
* </code></pre>
*
* @hide
*/
@Retention(CLASS)
@Target({ANNOTATION_TYPE})
public @interface StringDef {
/** Defines the allowed constants for this element */
String[] value() default {};
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be a String resource reference (e.g. {@link android.R.string#ok}).
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface StringRes {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that a integer parameter, field or method return value is expected
* to be a style resource reference (e.g. {@link android.R.style#TextAppearance}).
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface StyleRes {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that a integer parameter, field or method return value is expected
* to be a styleable resource reference (e.g. {@link android.R.styleable#TextView_text}).
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface StyleableRes {
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2012 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
/** Indicates that Lint should ignore the specified warnings for the annotated element. */
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.CLASS)
public @interface SuppressLint {
/**
* The set of warnings (identified by the lint issue id) that should be
* ignored by lint. It is not an error to specify an unrecognized name.
*/
String[] value();
}

View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2014 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
/**
* Indicates an API is exposed for use by bundled system applications.
* <p>
* These APIs are not guaranteed to remain consistent release-to-release,
* and are not for use by apps linking against the Android SDK.
* </p><p>
* This annotation should only appear on API that is already marked <pre>@hide</pre>.
* </p>
*
* @hide
*/
@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE})
@Retention(RetentionPolicy.SOURCE)
public @interface SystemApi {
}

View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2012 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
/** Indicates that Lint should treat this type as targeting a given API level, no matter what the
project target is. */
@Target({TYPE, METHOD, CONSTRUCTOR})
@Retention(RetentionPolicy.CLASS)
public @interface TargetApi {
/**
* This sets the target api level for the type..
*/
int value();
}

View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2015 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
/**
* Indicates an API is exposed for use by CTS.
* <p>
* These APIs are not guaranteed to remain consistent release-to-release,
* and are not for use by apps linking against the Android SDK.
* </p>
*
* @hide
*/
@Target({TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE})
@Retention(RetentionPolicy.SOURCE)
public @interface TestApi {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2015 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be a transition resource reference.
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface TransitionRes {
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2015 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that the annotated method or constructor should only be called on the UI thread.
* If the annotated element is a class, then all methods in the class should be called
* on the UI thread.
* <p>
* Example:
* <pre><code>
* &#64;UiThread
* public abstract void setText(@NonNull String text) { ... }
* </code></pre>
*
* {@hide}
*/
@Retention(SOURCE)
@Target({METHOD,CONSTRUCTOR,TYPE})
public @interface UiThread {
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2016 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that the annotated element is a multi-user user ID. This is
* <em>not</em> the same as a UID.
*
* @hide
*/
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface UserIdInt {
}

View File

@ -0,0 +1,37 @@
/*
* 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.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Indicates a class is a widget usable by application developers to create UI.
* <p>
* This must be used in cases where:
* <ul>
* <li>The widget is not in the package <code>android.widget</code></li>
* <li>The widget extends <code>android.view.ViewGroup</code></li>
* </ul>
* @hide
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.SOURCE)
public @interface Widget {
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2015 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.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that the annotated method should only be called on a worker thread.
* If the annotated element is a class, then all methods in the class should be called
* on a worker thread.
* <p>
* Example:
* <pre><code>
* &#64;WorkerThread
* protected abstract FilterResults performFiltering(CharSequence constraint);
* </code></pre>
*
* {@hide}
*/
@Retention(SOURCE)
@Target({METHOD,CONSTRUCTOR,TYPE})
public @interface WorkerThread {
}

View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2013 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Denotes that an integer parameter, field or method return value is expected
* to be an XML resource reference.
*
* {@hide}
*/
@Documented
@Retention(SOURCE)
@Target({METHOD, PARAMETER, FIELD})
public @interface XmlRes {
}

View File

@ -0,0 +1,284 @@
/*
* 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.annotation.CallSuper;
import android.content.*;
import android.content.res.Configuration;
import android.os.Bundle;
import java.util.ArrayList;
/**
* Base class for maintaining global application state. You can provide your own
* implementation by creating a subclass and specifying the fully-qualified name
* of this subclass as the <code>"android:name"</code> attribute in your
* AndroidManifest.xml's <code>&lt;application&gt;</code> tag. The Application
* class, or your subclass of the Application class, is instantiated before any
* other class when the process for your application/package is created.
*
* <p class="note"><strong>Note: </strong>There is normally no need to subclass
* Application. In most situations, static singletons can provide the same
* functionality in a more modular way. If your singleton needs a global
* context (for example to register broadcast receivers), include
* {@link android.content.Context#getApplicationContext() Context.getApplicationContext()}
* as a {@link android.content.Context} argument when invoking your singleton's
* <code>getInstance()</code> method.
* </p>
*/
public class Application extends ContextWrapper implements ComponentCallbacks2 {
private ArrayList<ComponentCallbacks> mComponentCallbacks =
new ArrayList<ComponentCallbacks>();
private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
new ArrayList<ActivityLifecycleCallbacks>();
private ArrayList<OnProvideAssistDataListener> mAssistCallbacks = null;
public interface ActivityLifecycleCallbacks {
void onActivityCreated(Activity activity, Bundle savedInstanceState);
void onActivityStarted(Activity activity);
void onActivityResumed(Activity activity);
void onActivityPaused(Activity activity);
void onActivityStopped(Activity activity);
void onActivitySaveInstanceState(Activity activity, Bundle outState);
void onActivityDestroyed(Activity activity);
}
/**
* Callback interface for use with {@link Application#registerOnProvideAssistDataListener}
* and {@link Application#unregisterOnProvideAssistDataListener}.
*/
public interface OnProvideAssistDataListener {
/**
* This is called when the user is requesting an assist, to build a full
* {@link Intent#ACTION_ASSIST} Intent with all of the context of the current
* application. You can override this method to place into the bundle anything
* you would like to appear in the {@link Intent#EXTRA_ASSIST_CONTEXT} part
* of the assist Intent.
*/
public void onProvideAssistData(Activity activity, Bundle data);
}
public Application() {
super(null);
}
/**
* Called when the application is starting, before any activity, service,
* or receiver objects (excluding content providers) have been created.
* Implementations should be as quick as possible (for example using
* lazy initialization of state) since the time spent in this function
* directly impacts the performance of starting the first activity,
* service, or receiver in a process.
* If you override this method, be sure to call super.onCreate().
*/
@CallSuper
public void onCreate() {
}
/**
* This method is for use in emulated process environments. It will
* never be called on a production Android device, where processes are
* removed by simply killing them; no user code (including this callback)
* is executed when doing so.
*/
@CallSuper
public void onTerminate() {
}
@CallSuper
public void onConfigurationChanged(Configuration newConfig) {
Object[] callbacks = collectComponentCallbacks();
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
((ComponentCallbacks)callbacks[i]).onConfigurationChanged(newConfig);
}
}
}
@CallSuper
public void onLowMemory() {
Object[] callbacks = collectComponentCallbacks();
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
((ComponentCallbacks)callbacks[i]).onLowMemory();
}
}
}
@CallSuper
public void onTrimMemory(int level) {
Object[] callbacks = collectComponentCallbacks();
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
Object c = callbacks[i];
if (c instanceof ComponentCallbacks2) {
((ComponentCallbacks2)c).onTrimMemory(level);
}
}
}
}
public void registerComponentCallbacks(ComponentCallbacks callback) {
synchronized (mComponentCallbacks) {
mComponentCallbacks.add(callback);
}
}
public void unregisterComponentCallbacks(ComponentCallbacks callback) {
synchronized (mComponentCallbacks) {
mComponentCallbacks.remove(callback);
}
}
public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
synchronized (mActivityLifecycleCallbacks) {
mActivityLifecycleCallbacks.add(callback);
}
}
public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
synchronized (mActivityLifecycleCallbacks) {
mActivityLifecycleCallbacks.remove(callback);
}
}
public void registerOnProvideAssistDataListener(OnProvideAssistDataListener callback) {
synchronized (this) {
if (mAssistCallbacks == null) {
mAssistCallbacks = new ArrayList<OnProvideAssistDataListener>();
}
mAssistCallbacks.add(callback);
}
}
public void unregisterOnProvideAssistDataListener(OnProvideAssistDataListener callback) {
synchronized (this) {
if (mAssistCallbacks != null) {
mAssistCallbacks.remove(callback);
}
}
}
// ------------------ Internal API ------------------
/**
* @hide
*/
public final void attach(Context context) {
attachBaseContext(context);
}
/* package */ void dispatchActivityCreated(Activity activity, Bundle savedInstanceState) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
((ActivityLifecycleCallbacks)callbacks[i]).onActivityCreated(activity,
savedInstanceState);
}
}
}
/* package */ void dispatchActivityStarted(Activity activity) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
((ActivityLifecycleCallbacks)callbacks[i]).onActivityStarted(activity);
}
}
}
/* package */ void dispatchActivityResumed(Activity activity) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
((ActivityLifecycleCallbacks)callbacks[i]).onActivityResumed(activity);
}
}
}
/* package */ void dispatchActivityPaused(Activity activity) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
((ActivityLifecycleCallbacks)callbacks[i]).onActivityPaused(activity);
}
}
}
/* package */ void dispatchActivityStopped(Activity activity) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
((ActivityLifecycleCallbacks)callbacks[i]).onActivityStopped(activity);
}
}
}
/* package */ void dispatchActivitySaveInstanceState(Activity activity, Bundle outState) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
((ActivityLifecycleCallbacks)callbacks[i]).onActivitySaveInstanceState(activity,
outState);
}
}
}
/* package */ void dispatchActivityDestroyed(Activity activity) {
Object[] callbacks = collectActivityLifecycleCallbacks();
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
((ActivityLifecycleCallbacks)callbacks[i]).onActivityDestroyed(activity);
}
}
}
private Object[] collectComponentCallbacks() {
Object[] callbacks = null;
synchronized (mComponentCallbacks) {
if (mComponentCallbacks.size() > 0) {
callbacks = mComponentCallbacks.toArray();
}
}
return callbacks;
}
private Object[] collectActivityLifecycleCallbacks() {
Object[] callbacks = null;
synchronized (mActivityLifecycleCallbacks) {
if (mActivityLifecycleCallbacks.size() > 0) {
callbacks = mActivityLifecycleCallbacks.toArray();
}
}
return callbacks;
}
/* package */ void dispatchOnProvideAssistData(Activity activity, Bundle data) {
Object[] callbacks;
synchronized (this) {
if (mAssistCallbacks == null) {
return;
}
callbacks = mAssistCallbacks.toArray();
}
if (callbacks != null) {
for (int i=0; i<callbacks.length; i++) {
((OnProvideAssistDataListener)callbacks[i]).onProvideAssistData(activity, data);
}
}
}
}

View File

@ -0,0 +1,24 @@
/*
* Copyright (C) 2014 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;
/** {@hide} */
public class PackageDeleteObserver {
public void onUserActionRequired(Intent intent) {
}
public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
}
}

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2014 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.os.Bundle;
/** {@hide} */
public class PackageInstallObserver {
public void onUserActionRequired(Intent intent) {
}
/**
* This method will be called to report the result of the package
* installation attempt.
*
* @param basePackageName Name of the package whose installation was
* attempted
* @param extras If non-null, this Bundle contains extras providing
* additional information about an install failure. See
* {@link android.content.pm.PackageManager} for documentation
* about which extras apply to various failures; in particular
* the strings named EXTRA_FAILURE_*.
* @param returnCode The numeric success or failure code indicating the
* basic outcome
* @hide
*/
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
}
}

View File

@ -0,0 +1,722 @@
/*
* 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.annotation.IntDef;
import android.annotation.Nullable;
import android.content.ComponentCallbacks2;
import android.content.Intent;
import android.content.ContextWrapper;
import android.content.Context;
import android.content.res.Configuration;
import android.os.IBinder;
import android.util.Log;
import kotlin.NotImplementedError;
import xyz.nulldev.androidcompat.service.ServiceSupport;
import xyz.nulldev.androidcompat.util.KodeinGlobalHelper;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* 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 implements ComponentCallbacks2 {
private static final ServiceSupport serviceSupport = KodeinGlobalHelper.instance(ServiceSupport.class);
private static final String TAG = "Service";
/**
* Flag for {@link #stopForeground(int)}: if set, the notification previously provided
* to {@link #startForeground} will be removed. Otherwise it will remain
* until a later call (to {@link #startForeground(int, Notification)} or
* {@link #stopForeground(int)} removes it, or the service is destroyed.
*/
public static final int STOP_FOREGROUND_REMOVE = 1<<0;
/**
* Flag for {@link #stopForeground(int)}: if set, the notification previously provided
* to {@link #startForeground} will be detached from the service. Only makes sense
* when {@link #STOP_FOREGROUND_REMOVE} is <b>not</b> set -- in this case, the notification
* will remain shown, but be completely detached from the service and so no longer changed
* except through direct calls to the notification manager.
*/
public static final int STOP_FOREGROUND_DETACH = 1<<1;
/** @hide */
@IntDef(flag = true,
value = {
STOP_FOREGROUND_REMOVE,
STOP_FOREGROUND_DETACH
})
@Retention(RetentionPolicy.SOURCE)
public @interface StopForegroundFlags {}
public Service() {
//==================[THIS LINE MODIFIED FROM ANDROID SOURCE!]==================
//Service must be initialized with a base context!
super(KodeinGlobalHelper.instance(Context.class));
}
/** Return the application that owns this service. */
public final Application getApplication() {
return mApplication;
}
/**
* 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) {
}
/**
* Bits returned by {@link #onStartCommand} describing how to continue
* the service if it is killed. May be {@link #START_STICKY},
* {@link #START_NOT_STICKY}, {@link #START_REDELIVER_INTENT},
* or {@link #START_STICKY_COMPATIBILITY}.
*/
public static final int START_CONTINUATION_MASK = 0xf;
/**
* Constant to return from {@link #onStartCommand}: compatibility
* version of {@link #START_STICKY} that does not guarantee that
* {@link #onStartCommand} will be called again after being killed.
*/
public static final int START_STICKY_COMPATIBILITY = 0;
/**
* Constant to return from {@link #onStartCommand}: if this service's
* process is killed while it is started (after returning from
* {@link #onStartCommand}), then leave it in the started state but
* don't retain this delivered intent. Later the system will try to
* re-create the service. Because it is in the started state, it will
* guarantee to call {@link #onStartCommand} after creating the new
* service instance; if there are not any pending start commands to be
* delivered to the service, it will be called with a null intent
* object, so you must take care to check for this.
*
* <p>This mode makes sense for things that will be explicitly started
* and stopped to run for arbitrary periods of time, such as a service
* performing background music playback.
*/
public static final int START_STICKY = 1;
/**
* Constant to return from {@link #onStartCommand}: if this service's
* process is killed while it is started (after returning from
* {@link #onStartCommand}), and there are no new start intents to
* deliver to it, then take the service out of the started state and
* don't recreate until a future explicit call to
* {@link Context#startService Context.startService(Intent)}. The
* service will not receive a {@link #onStartCommand(Intent, int, int)}
* call with a null Intent because it will not be re-started if there
* are no pending Intents to deliver.
*
* <p>This mode makes sense for things that want to do some work as a
* result of being started, but can be stopped when under memory pressure
* and will explicit start themselves again later to do more work. An
* example of such a service would be one that polls for data from
* a server: it could schedule an alarm to poll every N minutes by having
* the alarm start its service. When its {@link #onStartCommand} is
* called from the alarm, it schedules a new alarm for N minutes later,
* and spawns a thread to do its networking. If its process is killed
* while doing that check, the service will not be restarted until the
* alarm goes off.
*/
public static final int START_NOT_STICKY = 2;
/**
* Constant to return from {@link #onStartCommand}: if this service's
* process is killed while it is started (after returning from
* {@link #onStartCommand}), then it will be scheduled for a restart
* and the last delivered Intent re-delivered to it again via
* {@link #onStartCommand}. This Intent will remain scheduled for
* redelivery until the service calls {@link #stopSelf(int)} with the
* start ID provided to {@link #onStartCommand}. The
* service will not receive a {@link #onStartCommand(Intent, int, int)}
* call with a null Intent because it will will only be re-started if
* it is not finished processing all Intents sent to it (and any such
* pending events will be delivered at the point of restart).
*/
public static final int START_REDELIVER_INTENT = 3;
/** @hide */
@IntDef(flag = false,
value = {
START_STICKY_COMPATIBILITY,
START_STICKY,
START_NOT_STICKY,
START_REDELIVER_INTENT,
})
@Retention(RetentionPolicy.SOURCE)
public @interface StartResult {}
/**
* Special constant for reporting that we are done processing
* {@link #onTaskRemoved(Intent)}.
* @hide
*/
public static final int START_TASK_REMOVED_COMPLETE = 1000;
/**
* This flag is set in {@link #onStartCommand} if the Intent is a
* re-delivery of a previously delivered intent, because the service
* had previously returned {@link #START_REDELIVER_INTENT} but had been
* killed before calling {@link #stopSelf(int)} for that Intent.
*/
public static final int START_FLAG_REDELIVERY = 0x0001;
/**
* This flag is set in {@link #onStartCommand} if the Intent is a
* retry because the original attempt never got to or returned from
* {@link #onStartCommand(Intent, int, int)}.
*/
public static final int START_FLAG_RETRY = 0x0002;
/** @hide */
@IntDef(flag = true,
value = {
START_FLAG_REDELIVERY,
START_FLAG_RETRY,
})
@Retention(RetentionPolicy.SOURCE)
public @interface StartArgFlags {}
/**
* 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>If you need your application to run on platform versions prior to API
* level 5, you can use the following model to handle the older {@link #onStart}
* callback in that case. The <code>handleCommand</code> method is implemented by
* you as appropriate:
*
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
* start_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. Currently either
* 0, {@link #START_FLAG_REDELIVERY}, or {@link #START_FLAG_RETRY}.
* @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 @StartResult int onStartCommand(Intent intent, @StartArgFlags int flags, int startId) {
onStart(intent, startId);
return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
/**
* 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() {
}
public void onConfigurationChanged(Configuration newConfig) {
}
public void onLowMemory() {
}
public void onTrimMemory(int level) {
}
/**
* Return the communication channel to the service. May return null if
* clients can not bind to the service. The returned
* {@link android.os.IBinder} is usually for a complex interface
* that has been <a href="{@docRoot}guide/components/aidl.html">described using
* aidl</a>.
*
* <p><em>Note that unlike other application components, calls on to the
* IBinder interface returned here may not happen on the main thread
* of the process</em>. More information about the main thread can be found in
* <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html">Processes and
* Threads</a>.</p>
*
* @param intent The Intent that was used to bind to this service,
* as given to {@link android.content.Context#bindService
* Context.bindService}. Note that any extras that were included with
* the Intent at that point will <em>not</em> be seen here.
*
* @return Return an IBinder through which clients can call on to the
* service.
*/
@Nullable
public abstract IBinder onBind(Intent intent);
/**
* Called when all clients have disconnected from a particular interface
* published by the service. The default implementation does nothing and
* returns false.
*
* @param intent The Intent that was used to bind to this service,
* as given to {@link android.content.Context#bindService
* Context.bindService}. Note that any extras that were included with
* the Intent at that point will <em>not</em> be seen here.
*
* @return Return true if you would like to have the service's
* {@link #onRebind} method later called when new clients bind to it.
*/
public boolean onUnbind(Intent intent) {
return false;
}
/**
* Called when new clients have connected to the service, after it had
* previously been notified that all had disconnected in its
* {@link #onUnbind}. This will only be called if the implementation
* of {@link #onUnbind} was overridden to return true.
*
* @param intent The Intent that was used to bind to this service,
* as given to {@link android.content.Context#bindService
* Context.bindService}. Note that any extras that were included with
* the Intent at that point will <em>not</em> be seen here.
*/
public void onRebind(Intent intent) {
}
/**
* This is called if the service is currently running and the user has
* removed a task that comes from the service's application. If you have
* set {@link android.content.pm.ServiceInfo#FLAG_STOP_WITH_TASK ServiceInfo.FLAG_STOP_WITH_TASK}
* then you will not receive this callback; instead, the service will simply
* be stopped.
*
* @param rootIntent The original root Intent that was used to launch
* the task that is being removed.
*/
public void onTaskRemoved(Intent rootIntent) {
}
/**
* Stop the service, if it was previously started. This is the same as
* calling {@link android.content.Context#stopService} for this particular service.
*
* @see #stopSelfResult(int)
*/
public final void stopSelf() {
stopSelf(-1);
}
/**
* Old version of {@link #stopSelfResult} that doesn't return a result.
*
* @see #stopSelfResult
*/
public final void stopSelf(int startId) {
serviceSupport.stopSelf(this);
//TODO Do something with startId
}
/**
* Stop the service if the most recent time it was started was
* <var>startId</var>. This is the same as calling {@link
* android.content.Context#stopService} for this particular service but allows you to
* safely avoid stopping if there is a start request from a client that you
* haven't yet seen in {@link #onStart}.
*
* <p><em>Be careful about ordering of your calls to this function.</em>.
* If you call this function with the most-recently received ID before
* you have called it for previously received IDs, the service will be
* immediately stopped anyway. If you may end up processing IDs out
* of order (such as by dispatching them on separate threads), then you
* are responsible for stopping them in the same order you received them.</p>
*
* @param startId The most recent start identifier received in {@link
* #onStart}.
* @return Returns true if the startId matches the last start request
* and the service will be stopped, else false.
*
* @see #stopSelf()
*/
public final boolean stopSelfResult(int startId) {
stopSelf(startId);
//TODO Actually return result maybe
return true;
}
/**
* @deprecated This is a now a no-op, use
* {@link #startForeground(int, Notification)} instead. This method
* has been turned into a no-op rather than simply being deprecated
* because analysis of numerous poorly behaving devices has shown that
* increasingly often the trouble is being caused in part by applications
* that are abusing it. Thus, given a choice between introducing
* problems in existing applications using this API (by allowing them to
* be killed when they would like to avoid it), vs allowing the performance
* of the entire system to be decreased, this method was deemed less
* important.
*
* @hide
*/
@Deprecated
public final void setForeground(boolean isForeground) {
Log.w(TAG, "setForeground: ignoring old API call on " + getClass().getName());
}
/**
* Make this service run in the foreground, supplying the ongoing
* notification to be shown to the user while in this state.
* By default services are background, meaning that if the system needs to
* kill them to reclaim more memory (such as to display a large page in a
* web browser), they can be killed without too much harm. You can set this
* flag if killing your service would be disruptive to the user, such as
* if your service is performing background music playback, so the user
* would notice if their music stopped playing.
*
* <p>If you need your application to run on platform versions prior to API
* level 5, you can use the following model to call the the older setForeground()
* or this modern method as appropriate:
*
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
* foreground_compatibility}
*
* @param id The identifier for this notification as per
* {@link NotificationManager#notify(int, Notification)
* NotificationManager.notify(int, Notification)}; must not be 0.
* @param notification The Notification to be displayed.
*
* @see #stopForeground(boolean)
*/
public final void startForeground(int id, Notification notification) {
throw new NotImplementedError("TODO");
}
/**
* Synonym for {@link #stopForeground(int)}.
* @param removeNotification If true, the {@link #STOP_FOREGROUND_REMOVE} flag
* will be supplied.
* @see #stopForeground(int)
* @see #startForeground(int, Notification)
*/
public final void stopForeground(boolean removeNotification) {
stopForeground(removeNotification ? STOP_FOREGROUND_REMOVE : 0);
}
/**
* Remove this service from foreground state, allowing it to be killed if
* more memory is needed.
* @param flags Additional behavior options: {@link #STOP_FOREGROUND_REMOVE},
* {@link #STOP_FOREGROUND_DETACH}.
* @see #startForeground(int, Notification)
*/
public final void stopForeground(@StopForegroundFlags int flags) {
throw new NotImplementedError("TODO");
}
/**
* Print the Service's state into the given stream. This gets invoked if
* you run "adb shell dumpsys activity service &lt;yourservicename&gt;"
* (note that for this command to work, the service must be running, and
* you must specify a fully-qualified service name).
* This is distinct from "dumpsys &lt;servicename&gt;", which only works for
* named system services and which invokes the {@link IBinder#dump} method
* on the {@link IBinder} interface registered with ServiceManager.
*
* @param fd The raw file descriptor that the dump is being sent to.
* @param writer The PrintWriter to which you should dump your state. This will be
* closed for you after you return.
* @param args additional arguments to the dump request.
*/
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
writer.println("nothing to dump");
}
// ------------------ Internal API ------------------
final String getClassName() {
return mClassName;
}
// set by the thread after the constructor and before onCreate(Bundle icicle) is called.
private String mClassName = null;
private IBinder mToken = null;
private Application mApplication = null;
private boolean mStartCompatibility = false;
}

View File

@ -0,0 +1,109 @@
/*
* Copyright (C) 2017 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.arch.persistence.db;
import androidx.annotation.Nullable;
/**
* A basic implementation of {@link SupportSQLiteQuery} which receives a query and its args and
* binds args based on the passed in Object type.
*/
public final class SimpleSQLiteQuery implements SupportSQLiteQuery {
private final String mQuery;
@Nullable
private final Object[] mBindArgs;
/**
* Creates an SQL query with the sql string and the bind arguments.
*
* @param query The query string, can include bind arguments (.e.g ?).
* @param bindArgs The bind argument value that will replace the placeholders in the query.
*/
public SimpleSQLiteQuery(String query, @Nullable Object[] bindArgs) {
mQuery = query;
mBindArgs = bindArgs;
}
/**
* Creates an SQL query without any bind arguments.
*
* @param query The SQL query to execute. Cannot include bind parameters.
*/
public SimpleSQLiteQuery(String query) {
this(query, null);
}
/**
* Binds the given arguments into the given sqlite statement.
*
* @param statement The sqlite statement
* @param bindArgs The list of bind arguments
*/
public static void bind(SupportSQLiteProgram statement, Object[] bindArgs) {
if (bindArgs == null) {
return;
}
final int limit = bindArgs.length;
for (int i = 0; i < limit; i++) {
final Object arg = bindArgs[i];
bind(statement, i + 1, arg);
}
}
private static void bind(SupportSQLiteProgram statement, int index, Object arg) {
// extracted from android.database.sqlite.SQLiteConnection
if (arg == null) {
statement.bindNull(index);
} else if (arg instanceof byte[]) {
statement.bindBlob(index, (byte[]) arg);
} else if (arg instanceof Float) {
statement.bindDouble(index, (Float) arg);
} else if (arg instanceof Double) {
statement.bindDouble(index, (Double) arg);
} else if (arg instanceof Long) {
statement.bindLong(index, (Long) arg);
} else if (arg instanceof Integer) {
statement.bindLong(index, (Integer) arg);
} else if (arg instanceof Short) {
statement.bindLong(index, (Short) arg);
} else if (arg instanceof Byte) {
statement.bindLong(index, (Byte) arg);
} else if (arg instanceof String) {
statement.bindString(index, (String) arg);
} else if (arg instanceof Boolean) {
statement.bindLong(index, ((Boolean) arg) ? 1 : 0);
} else {
throw new IllegalArgumentException("Cannot bind " + arg + " at index " + index
+ " Supported types: null, byte[], float, double, long, int, short, byte,"
+ " string");
}
}
@Override
public String getSql() {
return mQuery;
}
@Override
public void bindTo(SupportSQLiteProgram statement) {
bind(statement, mBindArgs);
}
@Override
public int getArgCount() {
return mBindArgs == null ? 0 : mBindArgs.length;
}
}

View File

@ -0,0 +1,604 @@
/*
* Copyright (C) 2016 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.arch.persistence.db;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteTransactionListener;
import android.os.Build;
import android.os.CancellationSignal;
import android.os.OperationCanceledException;
import android.util.Pair;
import androidx.annotation.RequiresApi;
import java.io.Closeable;
import java.util.List;
import java.util.Locale;
/**
* A database abstraction which removes the framework dependency and allows swapping underlying
* sql versions. It mimics the behavior of {@link android.database.sqlite.SQLiteDatabase}
*/
@SuppressWarnings("unused")
public interface SupportSQLiteDatabase extends Closeable {
/**
* Compiles the given SQL statement.
*
* @param sql The sql query.
* @return Compiled statement.
*/
SupportSQLiteStatement compileStatement(String sql);
/**
* Begins a transaction in EXCLUSIVE mode.
* <p>
* Transactions can be nested.
* When the outer transaction is ended all of
* the work done in that transaction and all of the nested transactions will be committed or
* rolled back. The changes will be rolled back if any transaction is ended without being
* marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
* </p>
* <p>Here is the standard idiom for transactions:
*
* <pre>
* db.beginTransaction();
* try {
* ...
* db.setTransactionSuccessful();
* } finally {
* db.endTransaction();
* }
* </pre>
*/
void beginTransaction();
/**
* Begins a transaction in IMMEDIATE mode. Transactions can be nested. When
* the outer transaction is ended all of the work done in that transaction
* and all of the nested transactions will be committed or rolled back. The
* changes will be rolled back if any transaction is ended without being
* marked as clean (by calling setTransactionSuccessful). Otherwise they
* will be committed.
* <p>
* Here is the standard idiom for transactions:
*
* <pre>
* db.beginTransactionNonExclusive();
* try {
* ...
* db.setTransactionSuccessful();
* } finally {
* db.endTransaction();
* }
* </pre>
*/
void beginTransactionNonExclusive();
/**
* Begins a transaction in EXCLUSIVE mode.
* <p>
* Transactions can be nested.
* When the outer transaction is ended all of
* the work done in that transaction and all of the nested transactions will be committed or
* rolled back. The changes will be rolled back if any transaction is ended without being
* marked as clean (by calling setTransactionSuccessful). Otherwise they will be committed.
* </p>
* <p>Here is the standard idiom for transactions:
*
* <pre>
* db.beginTransactionWithListener(listener);
* try {
* ...
* db.setTransactionSuccessful();
* } finally {
* db.endTransaction();
* }
* </pre>
*
* @param transactionListener listener that should be notified when the transaction begins,
* commits, or is rolled back, either explicitly or by a call to
* {@link #yieldIfContendedSafely}.
*/
void beginTransactionWithListener(SQLiteTransactionListener transactionListener);
/**
* Begins a transaction in IMMEDIATE mode. Transactions can be nested. When
* the outer transaction is ended all of the work done in that transaction
* and all of the nested transactions will be committed or rolled back. The
* changes will be rolled back if any transaction is ended without being
* marked as clean (by calling setTransactionSuccessful). Otherwise they
* will be committed.
* <p>
* Here is the standard idiom for transactions:
*
* <pre>
* db.beginTransactionWithListenerNonExclusive(listener);
* try {
* ...
* db.setTransactionSuccessful();
* } finally {
* db.endTransaction();
* }
* </pre>
*
* @param transactionListener listener that should be notified when the
* transaction begins, commits, or is rolled back, either
* explicitly or by a call to {@link #yieldIfContendedSafely}.
*/
void beginTransactionWithListenerNonExclusive(SQLiteTransactionListener transactionListener);
/**
* End a transaction. See beginTransaction for notes about how to use this and when transactions
* are committed and rolled back.
*/
void endTransaction();
/**
* Marks the current transaction as successful. Do not do any more database work between
* calling this and calling endTransaction. Do as little non-database work as possible in that
* situation too. If any errors are encountered between this and endTransaction the transaction
* will still be committed.
*
* @throws IllegalStateException if the current thread is not in a transaction or the
* transaction is already marked as successful.
*/
void setTransactionSuccessful();
/**
* Returns true if the current thread has a transaction pending.
*
* @return True if the current thread is in a transaction.
*/
boolean inTransaction();
/**
* Returns true if the current thread is holding an active connection to the database.
* <p>
* The name of this method comes from a time when having an active connection
* to the database meant that the thread was holding an actual lock on the
* database. Nowadays, there is no longer a true "database lock" although threads
* may block if they cannot acquire a database connection to perform a
* particular operation.
* </p>
*
* @return True if the current thread is holding an active connection to the database.
*/
boolean isDbLockedByCurrentThread();
/**
* Temporarily end the transaction to let other threads run. The transaction is assumed to be
* successful so far. Do not call setTransactionSuccessful before calling this. When this
* returns a new transaction will have been created but not marked as successful. This assumes
* that there are no nested transactions (beginTransaction has only been called once) and will
* throw an exception if that is not the case.
*
* @return true if the transaction was yielded
*/
boolean yieldIfContendedSafely();
/**
* Temporarily end the transaction to let other threads run. The transaction is assumed to be
* successful so far. Do not call setTransactionSuccessful before calling this. When this
* returns a new transaction will have been created but not marked as successful. This assumes
* that there are no nested transactions (beginTransaction has only been called once) and will
* throw an exception if that is not the case.
*
* @param sleepAfterYieldDelay if > 0, sleep this long before starting a new transaction if
* the lock was actually yielded. This will allow other background
* threads to make some
* more progress than they would if we started the transaction
* immediately.
* @return true if the transaction was yielded
*/
boolean yieldIfContendedSafely(long sleepAfterYieldDelay);
/**
* Gets the database version.
*
* @return the database version
*/
int getVersion();
/**
* Sets the database version.
*
* @param version the new database version
*/
void setVersion(int version);
/**
* Returns the maximum size the database may grow to.
*
* @return the new maximum database size
*/
long getMaximumSize();
/**
* Sets the maximum size the database will grow to. The maximum size cannot
* be set below the current size.
*
* @param numBytes the maximum database size, in bytes
* @return the new maximum database size
*/
long setMaximumSize(long numBytes);
/**
* Returns the current database page size, in bytes.
*
* @return the database page size, in bytes
*/
long getPageSize();
/**
* Sets the database page size. The page size must be a power of two. This
* method does not work if any data has been written to the database file,
* and must be called right after the database has been created.
*
* @param numBytes the database page size, in bytes
*/
void setPageSize(long numBytes);
/**
* Runs the given query on the database. If you would like to have typed bind arguments,
* use {@link #query(SupportSQLiteQuery)}.
*
* @param query The SQL query that includes the query and can bind into a given compiled
* program.
* @return A {@link Cursor} object, which is positioned before the first entry. Note that
* {@link Cursor}s are not synchronized, see the documentation for more details.
* @see #query(SupportSQLiteQuery)
*/
Cursor query(String query);
/**
* Runs the given query on the database. If you would like to have bind arguments,
* use {@link #query(SupportSQLiteQuery)}.
*
* @param query The SQL query that includes the query and can bind into a given compiled
* program.
* @param bindArgs The query arguments to bind.
* @return A {@link Cursor} object, which is positioned before the first entry. Note that
* {@link Cursor}s are not synchronized, see the documentation for more details.
* @see #query(SupportSQLiteQuery)
*/
Cursor query(String query, Object[] bindArgs);
/**
* Runs the given query on the database.
* <p>
* This class allows using type safe sql program bindings while running queries.
*
* @param query The SQL query that includes the query and can bind into a given compiled
* program.
* @return A {@link Cursor} object, which is positioned before the first entry. Note that
* {@link Cursor}s are not synchronized, see the documentation for more details.
* @see SimpleSQLiteQuery
*/
Cursor query(SupportSQLiteQuery query);
/**
* Runs the given query on the database.
* <p>
* This class allows using type safe sql program bindings while running queries.
*
* @param query The SQL query that includes the query and can bind into a given compiled
* program.
* @param cancellationSignal A signal to cancel the operation in progress, or null if none.
* If the operation is canceled, then {@link OperationCanceledException} will be thrown
* when the query is executed.
* @return A {@link Cursor} object, which is positioned before the first entry. Note that
* {@link Cursor}s are not synchronized, see the documentation for more details.
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
Cursor query(SupportSQLiteQuery query, CancellationSignal cancellationSignal);
/**
* Convenience method for inserting a row into the database.
*
* @param table the table to insert the row into
* @param values this map contains the initial column values for the
* row. The keys should be the column names and the values the
* column values
* @param conflictAlgorithm for insert conflict resolver. One of
* {@link SQLiteDatabase#CONFLICT_NONE}, {@link SQLiteDatabase#CONFLICT_ROLLBACK},
* {@link SQLiteDatabase#CONFLICT_ABORT}, {@link SQLiteDatabase#CONFLICT_FAIL},
* {@link SQLiteDatabase#CONFLICT_IGNORE}, {@link SQLiteDatabase#CONFLICT_REPLACE}.
* @return the row ID of the newly inserted row, or -1 if an error occurred
* @throws SQLException If the insert fails
*/
long insert(String table, int conflictAlgorithm, ContentValues values) throws SQLException;
/**
* Convenience method for deleting rows in the database.
*
* @param table the table to delete from
* @param whereClause the optional WHERE clause to apply when deleting.
* Passing null will delete all rows.
* @param whereArgs You may include ?s in the where clause, which
* will be replaced by the values from whereArgs. The values
* will be bound as Strings.
* @return the number of rows affected if a whereClause is passed in, 0
* otherwise. To remove all rows and get a count pass "1" as the
* whereClause.
*/
int delete(String table, String whereClause, Object[] whereArgs);
/**
* Convenience method for updating rows in the database.
*
* @param table the table to update in
* @param conflictAlgorithm for update conflict resolver. One of
* {@link SQLiteDatabase#CONFLICT_NONE}, {@link SQLiteDatabase#CONFLICT_ROLLBACK},
* {@link SQLiteDatabase#CONFLICT_ABORT}, {@link SQLiteDatabase#CONFLICT_FAIL},
* {@link SQLiteDatabase#CONFLICT_IGNORE}, {@link SQLiteDatabase#CONFLICT_REPLACE}.
* @param values a map from column names to new column values. null is a
* valid value that will be translated to NULL.
* @param whereClause the optional WHERE clause to apply when updating.
* Passing null will update all rows.
* @param whereArgs You may include ?s in the where clause, which
* will be replaced by the values from whereArgs. The values
* will be bound as Strings.
* @return the number of rows affected
*/
int update(String table, int conflictAlgorithm,
ContentValues values, String whereClause, Object[] whereArgs);
/**
* Execute a single SQL statement that does not return any data.
* <p>
* When using {@link #enableWriteAheadLogging()}, journal_mode is
* automatically managed by this class. So, do not set journal_mode
* using "PRAGMA journal_mode'<value>" statement if your app is using
* {@link #enableWriteAheadLogging()}
* </p>
*
* @param sql the SQL statement to be executed. Multiple statements separated by semicolons are
* not supported.
* @throws SQLException if the SQL string is invalid
* @see #query(SupportSQLiteQuery)
*/
void execSQL(String sql) throws SQLException;
/**
* Execute a single SQL statement that does not return any data.
* <p>
* When using {@link #enableWriteAheadLogging()}, journal_mode is
* automatically managed by this class. So, do not set journal_mode
* using "PRAGMA journal_mode'<value>" statement if your app is using
* {@link #enableWriteAheadLogging()}
* </p>
*
* @param sql the SQL statement to be executed. Multiple statements separated by semicolons
* are
* not supported.
* @param bindArgs only byte[], String, Long and Double are supported in selectionArgs.
* @throws SQLException if the SQL string is invalid
* @see #query(SupportSQLiteQuery)
*/
void execSQL(String sql, Object[] bindArgs) throws SQLException;
/**
* Returns true if the database is opened as read only.
*
* @return True if database is opened as read only.
*/
boolean isReadOnly();
/**
* Returns true if the database is currently open.
*
* @return True if the database is currently open (has not been closed).
*/
boolean isOpen();
/**
* Returns true if the new version code is greater than the current database version.
*
* @param newVersion The new version code.
* @return True if the new version code is greater than the current database version.
*/
boolean needUpgrade(int newVersion);
/**
* Gets the path to the database file.
*
* @return The path to the database file.
*/
String getPath();
/**
* Sets the locale for this database. Does nothing if this database has
* the {@link SQLiteDatabase#NO_LOCALIZED_COLLATORS} flag set or was opened read only.
*
* @param locale The new locale.
* @throws SQLException if the locale could not be set. The most common reason
* for this is that there is no collator available for the locale you
* requested.
* In this case the database remains unchanged.
*/
void setLocale(Locale locale);
/**
* Sets the maximum size of the prepared-statement cache for this database.
* (size of the cache = number of compiled-sql-statements stored in the cache).
* <p>
* Maximum cache size can ONLY be increased from its current size (default = 10).
* If this method is called with smaller size than the current maximum value,
* then IllegalStateException is thrown.
* <p>
* This method is thread-safe.
*
* @param cacheSize the size of the cache. can be (0 to
* {@link SQLiteDatabase#MAX_SQL_CACHE_SIZE})
* @throws IllegalStateException if input cacheSize gt;
* {@link SQLiteDatabase#MAX_SQL_CACHE_SIZE}.
*/
void setMaxSqlCacheSize(int cacheSize);
/**
* Sets whether foreign key constraints are enabled for the database.
* <p>
* By default, foreign key constraints are not enforced by the database.
* This method allows an application to enable foreign key constraints.
* It must be called each time the database is opened to ensure that foreign
* key constraints are enabled for the session.
* </p><p>
* A good time to call this method is right after calling {@code #openOrCreateDatabase}
* or in the {@link SupportSQLiteOpenHelper.Callback#onConfigure} callback.
* </p><p>
* When foreign key constraints are disabled, the database does not check whether
* changes to the database will violate foreign key constraints. Likewise, when
* foreign key constraints are disabled, the database will not execute cascade
* delete or update triggers. As a result, it is possible for the database
* state to become inconsistent. To perform a database integrity check,
* call {@link #isDatabaseIntegrityOk}.
* </p><p>
* This method must not be called while a transaction is in progress.
* </p><p>
* See also <a href="http://sqlite.org/foreignkeys.html">SQLite Foreign Key Constraints</a>
* for more details about foreign key constraint support.
* </p>
*
* @param enable True to enable foreign key constraints, false to disable them.
* @throws IllegalStateException if the are transactions is in progress
* when this method is called.
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
void setForeignKeyConstraintsEnabled(boolean enable);
/**
* This method enables parallel execution of queries from multiple threads on the
* same database. It does this by opening multiple connections to the database
* and using a different database connection for each query. The database
* journal mode is also changed to enable writes to proceed concurrently with reads.
* <p>
* When write-ahead logging is not enabled (the default), it is not possible for
* reads and writes to occur on the database at the same time. Before modifying the
* database, the writer implicitly acquires an exclusive lock on the database which
* prevents readers from accessing the database until the write is completed.
* </p><p>
* In contrast, when write-ahead logging is enabled (by calling this method), write
* operations occur in a separate log file which allows reads to proceed concurrently.
* While a write is in progress, readers on other threads will perceive the state
* of the database as it was before the write began. When the write completes, readers
* on other threads will then perceive the new state of the database.
* </p><p>
* It is a good idea to enable write-ahead logging whenever a database will be
* concurrently accessed and modified by multiple threads at the same time.
* However, write-ahead logging uses significantly more memory than ordinary
* journaling because there are multiple connections to the same database.
* So if a database will only be used by a single thread, or if optimizing
* concurrency is not very important, then write-ahead logging should be disabled.
* </p><p>
* After calling this method, execution of queries in parallel is enabled as long as
* the database remains open. To disable execution of queries in parallel, either
* call {@link #disableWriteAheadLogging} or close the database and reopen it.
* </p><p>
* The maximum number of connections used to execute queries in parallel is
* dependent upon the device memory and possibly other properties.
* </p><p>
* If a query is part of a transaction, then it is executed on the same database handle the
* transaction was begun.
* </p><p>
* Writers should use {@link #beginTransactionNonExclusive()} or
* {@link #beginTransactionWithListenerNonExclusive(SQLiteTransactionListener)}
* to start a transaction. Non-exclusive mode allows database file to be in readable
* by other threads executing queries.
* </p><p>
* If the database has any attached databases, then execution of queries in parallel is NOT
* possible. Likewise, write-ahead logging is not supported for read-only databases
* or memory databases. In such cases, {@code enableWriteAheadLogging} returns false.
* </p><p>
* The best way to enable write-ahead logging is to pass the
* {@link SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING} flag to
* {@link SQLiteDatabase#openDatabase}. This is more efficient than calling
* <code><pre>
* SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory,
* SQLiteDatabase.CREATE_IF_NECESSARY | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING,
* myDatabaseErrorHandler);
* db.enableWriteAheadLogging();
* </pre></code>
* </p><p>
* Another way to enable write-ahead logging is to call {@code enableWriteAheadLogging}
* after opening the database.
* <code><pre>
* SQLiteDatabase db = SQLiteDatabase.openDatabase("db_filename", cursorFactory,
* SQLiteDatabase.CREATE_IF_NECESSARY, myDatabaseErrorHandler);
* db.enableWriteAheadLogging();
* </pre></code>
* </p><p>
* See also <a href="http://sqlite.org/wal.html">SQLite Write-Ahead Logging</a> for
* more details about how write-ahead logging works.
* </p>
*
* @return True if write-ahead logging is enabled.
* @throws IllegalStateException if there are transactions in progress at the
* time this method is called. WAL mode can only be changed when
* there are no
* transactions in progress.
* @see SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING
* @see #disableWriteAheadLogging
*/
boolean enableWriteAheadLogging();
/**
* This method disables the features enabled by {@link #enableWriteAheadLogging()}.
*
* @throws IllegalStateException if there are transactions in progress at the
* time this method is called. WAL mode can only be changed when
* there are no
* transactions in progress.
* @see #enableWriteAheadLogging
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
void disableWriteAheadLogging();
/**
* Returns true if write-ahead logging has been enabled for this database.
*
* @return True if write-ahead logging has been enabled for this database.
* @see #enableWriteAheadLogging
* @see SQLiteDatabase#ENABLE_WRITE_AHEAD_LOGGING
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
boolean isWriteAheadLoggingEnabled();
/**
* Returns list of full path names of all attached databases including the main database
* by executing 'pragma database_list' on the database.
*
* @return ArrayList of pairs of (database name, database file path) or null if the database
* is not open.
*/
List<Pair<String, String>> getAttachedDbs();
/**
* Runs 'pragma integrity_check' on the given database (and all the attached databases)
* and returns true if the given database (and all its attached databases) pass integrity_check,
* false otherwise.
* <p>
* If the result is false, then this method logs the errors reported by the integrity_check
* command execution.
* <p>
* Note that 'pragma integrity_check' on a database can take a long time.
*
* @return true if the given database (and all its attached databases) pass integrity_check,
* false otherwise.
*/
boolean isDatabaseIntegrityOk();
}

View File

@ -0,0 +1,389 @@
package android.arch.persistence.db;
/*
* Copyright (C) 2016 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.
*/
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.os.Build;
import android.util.Log;
import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import java.io.File;
import java.io.IOException;
import java.util.List;
// TODO Replace with androidx variant once Tachiyomi updates
/**
* An interface to map the behavior of {@link android.database.sqlite.SQLiteOpenHelper}.
* Note that since that class requires overriding certain methods, support implementation
* uses {@link Factory#create(Configuration)} to create this and {@link Callback} to implement
* the methods that should be overridden.
*/
@SuppressWarnings("unused")
public interface SupportSQLiteOpenHelper {
/**
* Return the name of the SQLite database being opened, as given to
* the constructor.
*/
String getDatabaseName();
/**
* Enables or disables the use of write-ahead logging for the database.
* <p>
* Write-ahead logging cannot be used with read-only databases so the value of
* this flag is ignored if the database is opened read-only.
*
* @param enabled True if write-ahead logging should be enabled, false if it
* should be disabled.
* @see SupportSQLiteDatabase#enableWriteAheadLogging()
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
void setWriteAheadLoggingEnabled(boolean enabled);
/**
* Create and/or open a database that will be used for reading and writing.
* The first time this is called, the database will be opened and
* {@link Callback#onCreate}, {@link Callback#onUpgrade} and/or {@link Callback#onOpen} will be
* called.
*
* <p>Once opened successfully, the database is cached, so you can
* call this method every time you need to write to the database.
* (Make sure to call {@link #close} when you no longer need the database.)
* Errors such as bad permissions or a full disk may cause this method
* to fail, but future attempts may succeed if the problem is fixed.</p>
*
* <p class="caution">Database upgrade may take a long time, you
* should not call this method from the application main thread, including
* from {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
*
* @return a read/write database object valid until {@link #close} is called
* @throws SQLiteException if the database cannot be opened for writing
*/
SupportSQLiteDatabase getWritableDatabase();
/**
* Create and/or open a database. This will be the same object returned by
* {@link #getWritableDatabase} unless some problem, such as a full disk,
* requires the database to be opened read-only. In that case, a read-only
* database object will be returned. If the problem is fixed, a future call
* to {@link #getWritableDatabase} may succeed, in which case the read-only
* database object will be closed and the read/write object will be returned
* in the future.
*
* <p class="caution">Like {@link #getWritableDatabase}, this method may
* take a long time to return, so you should not call it from the
* application main thread, including from
* {@link android.content.ContentProvider#onCreate ContentProvider.onCreate()}.
*
* @return a database object valid until {@link #getWritableDatabase}
* or {@link #close} is called.
* @throws SQLiteException if the database cannot be opened
*/
SupportSQLiteDatabase getReadableDatabase();
/**
* Close any open database object.
*/
void close();
/**
* Factory class to create instances of {@link SupportSQLiteOpenHelper} using
* {@link Configuration}.
*/
interface Factory {
/**
* Creates an instance of {@link SupportSQLiteOpenHelper} using the given configuration.
*
* @param configuration The configuration to use while creating the open helper.
* @return A SupportSQLiteOpenHelper which can be used to open a database.
*/
SupportSQLiteOpenHelper create(Configuration configuration);
}
/**
* Handles various lifecycle events for the SQLite connection, similar to
* {@link android.database.sqlite.SQLiteOpenHelper}.
*/
@SuppressWarnings({"unused", "WeakerAccess"})
abstract class Callback {
private static final String TAG = "SupportSQLite";
/**
* Version number of the database (starting at 1); if the database is older,
* {@link SupportSQLiteOpenHelper.Callback#onUpgrade(SupportSQLiteDatabase, int, int)}
* will be used to upgrade the database; if the database is newer,
* {@link SupportSQLiteOpenHelper.Callback#onDowngrade(SupportSQLiteDatabase, int, int)}
* will be used to downgrade the database.
*/
public final int version;
/**
* Creates a new Callback to get database lifecycle events.
*
* @param version The version for the database instance. See {@link #version}.
*/
public Callback(int version) {
this.version = version;
}
/**
* Called when the database connection is being configured, to enable features such as
* write-ahead logging or foreign key support.
* <p>
* This method is called before {@link #onCreate}, {@link #onUpgrade}, {@link #onDowngrade},
* or {@link #onOpen} are called. It should not modify the database except to configure the
* database connection as required.
* </p>
* <p>
* This method should only call methods that configure the parameters of the database
* connection, such as {@link SupportSQLiteDatabase#enableWriteAheadLogging}
* {@link SupportSQLiteDatabase#setForeignKeyConstraintsEnabled},
* {@link SupportSQLiteDatabase#setLocale},
* {@link SupportSQLiteDatabase#setMaximumSize}, or executing PRAGMA statements.
* </p>
*
* @param db The database.
*/
public void onConfigure(SupportSQLiteDatabase db) {
}
/**
* Called when the database is created for the first time. This is where the
* creation of tables and the initial population of the tables should happen.
*
* @param db The database.
*/
public abstract void onCreate(SupportSQLiteDatabase db);
/**
* Called when the database needs to be upgraded. The implementation
* should use this method to drop tables, add tables, or do anything else it
* needs to upgrade to the new schema version.
*
* <p>
* The SQLite ALTER TABLE documentation can be found
* <a href="http://sqlite.org/lang_altertable.html">here</a>. If you add new columns
* you can use ALTER TABLE to insert them into a live table. If you rename or remove columns
* you can use ALTER TABLE to rename the old table, then create the new table and then
* populate the new table with the contents of the old table.
* </p><p>
* This method executes within a transaction. If an exception is thrown, all changes
* will automatically be rolled back.
* </p>
*
* @param db The database.
* @param oldVersion The old database version.
* @param newVersion The new database version.
*/
public abstract void onUpgrade(SupportSQLiteDatabase db, int oldVersion, int newVersion);
/**
* Called when the database needs to be downgraded. This is strictly similar to
* {@link #onUpgrade} method, but is called whenever current version is newer than requested
* one.
* However, this method is not abstract, so it is not mandatory for a customer to
* implement it. If not overridden, default implementation will reject downgrade and
* throws SQLiteException
*
* <p>
* This method executes within a transaction. If an exception is thrown, all changes
* will automatically be rolled back.
* </p>
*
* @param db The database.
* @param oldVersion The old database version.
* @param newVersion The new database version.
*/
public void onDowngrade(SupportSQLiteDatabase db, int oldVersion, int newVersion) {
throw new SQLiteException("Can't downgrade database from version "
+ oldVersion + " to " + newVersion);
}
/**
* Called when the database has been opened. The implementation
* should check {@link SupportSQLiteDatabase#isReadOnly} before updating the
* database.
* <p>
* This method is called after the database connection has been configured
* and after the database schema has been created, upgraded or downgraded as necessary.
* If the database connection must be configured in some way before the schema
* is created, upgraded, or downgraded, do it in {@link #onConfigure} instead.
* </p>
*
* @param db The database.
*/
public void onOpen(SupportSQLiteDatabase db) {
}
/**
* The method invoked when database corruption is detected. Default implementation will
* delete the database file.
*
* @param db the {@link SupportSQLiteDatabase} object representing the database on which
* corruption is detected.
*/
public void onCorruption(SupportSQLiteDatabase db) {
// the following implementation is taken from {@link DefaultDatabaseErrorHandler}.
Log.e(TAG, "Corruption reported by sqlite on database: " + db.getPath());
// is the corruption detected even before database could be 'opened'?
if (!db.isOpen()) {
// database files are not even openable. delete this database file.
// NOTE if the database has attached databases, then any of them could be corrupt.
// and not deleting all of them could cause corrupted database file to remain and
// make the application crash on database open operation. To avoid this problem,
// the application should provide its own {@link DatabaseErrorHandler} impl class
// to delete ALL files of the database (including the attached databases).
deleteDatabaseFile(db.getPath());
return;
}
List<Pair<String, String>> attachedDbs = null;
try {
// Close the database, which will cause subsequent operations to fail.
// before that, get the attached database list first.
try {
attachedDbs = db.getAttachedDbs();
} catch (SQLiteException e) {
/* ignore */
}
try {
db.close();
} catch (IOException e) {
/* ignore */
}
} finally {
// Delete all files of this corrupt database and/or attached databases
if (attachedDbs != null) {
for (Pair<String, String> p : attachedDbs) {
deleteDatabaseFile(p.second);
}
} else {
// attachedDbs = null is possible when the database is so corrupt that even
// "PRAGMA database_list;" also fails. delete the main database file
deleteDatabaseFile(db.getPath());
}
}
}
private void deleteDatabaseFile(String fileName) {
if (fileName.equalsIgnoreCase(":memory:") || fileName.trim().length() == 0) {
return;
}
Log.w(TAG, "deleting the database file: " + fileName);
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
SQLiteDatabase.deleteDatabase(new File(fileName));
} else {
try {
final boolean deleted = new File(fileName).delete();
if (!deleted) {
Log.e(TAG, "Could not delete the database file " + fileName);
}
} catch (Exception error) {
Log.e(TAG, "error while deleting corrupted database file", error);
}
}
} catch (Exception e) {
/* print warning and ignore exception */
Log.w(TAG, "delete failed: ", e);
}
}
}
/**
* The configuration to create an SQLite open helper object using {@link Factory}.
*/
@SuppressWarnings("WeakerAccess")
class Configuration {
/**
* Context to use to open or create the database.
*/
@NonNull
public final Context context;
/**
* Name of the database file, or null for an in-memory database.
*/
@Nullable
public final String name;
/**
* The callback class to handle creation, upgrade and downgrade.
*/
@NonNull
public final SupportSQLiteOpenHelper.Callback callback;
Configuration(@NonNull Context context, @Nullable String name, @NonNull Callback callback) {
this.context = context;
this.name = name;
this.callback = callback;
}
/**
* Creates a new Configuration.Builder to create an instance of Configuration.
*
* @param context to use to open or create the database.
*/
public static Builder builder(Context context) {
return new Builder(context);
}
/**
* Builder class for {@link Configuration}.
*/
public static class Builder {
Context mContext;
String mName;
SupportSQLiteOpenHelper.Callback mCallback;
Builder(@NonNull Context context) {
mContext = context;
}
public Configuration build() {
if (mCallback == null) {
throw new IllegalArgumentException("Must set a callback to create the"
+ " configuration.");
}
if (mContext == null) {
throw new IllegalArgumentException("Must set a non-null context to create"
+ " the configuration.");
}
return new Configuration(mContext, mName, mCallback);
}
/**
* @param name Name of the database file, or null for an in-memory database.
* @return This
*/
public Builder name(@Nullable String name) {
mName = name;
return this;
}
/**
* @param callback The callback class to handle creation, upgrade and downgrade.
* @return this
*/
public Builder callback(@NonNull Callback callback) {
mCallback = callback;
return this;
}
}
}
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (C) 2016 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.arch.persistence.db;
import java.io.Closeable;
/**
* An interface to map the behavior of {@link android.database.sqlite.SQLiteProgram}.
*/
@SuppressWarnings("unused")
public interface SupportSQLiteProgram extends Closeable {
/**
* Bind a NULL value to this statement. The value remains bound until
* {@link #clearBindings} is called.
*
* @param index The 1-based index to the parameter to bind null to
*/
void bindNull(int index);
/**
* Bind a long value to this statement. The value remains bound until
* {@link #clearBindings} is called.
* addToBindArgs
*
* @param index The 1-based index to the parameter to bind
* @param value The value to bind
*/
void bindLong(int index, long value);
/**
* Bind a double value to this statement. The value remains bound until
* {@link #clearBindings} is called.
*
* @param index The 1-based index to the parameter to bind
* @param value The value to bind
*/
void bindDouble(int index, double value);
/**
* Bind a String value to this statement. The value remains bound until
* {@link #clearBindings} is called.
*
* @param index The 1-based index to the parameter to bind
* @param value The value to bind, must not be null
*/
void bindString(int index, String value);
/**
* Bind a byte array value to this statement. The value remains bound until
* {@link #clearBindings} is called.
*
* @param index The 1-based index to the parameter to bind
* @param value The value to bind, must not be null
*/
void bindBlob(int index, byte[] value);
/**
* Clears all existing bindings. Unset bindings are treated as NULL.
*/
void clearBindings();
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2017 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.arch.persistence.db;
/**
* A query with typed bindings. It is better to use this API instead of
* {@link android.database.sqlite.SQLiteDatabase#rawQuery(String, String[])} because it allows
* binding type safe parameters.
*/
public interface SupportSQLiteQuery {
/**
* The SQL query. This query can have placeholders(?) for bind arguments.
*
* @return The SQL query to compile
*/
String getSql();
/**
* Callback to bind the query parameters to the compiled statement.
*
* @param statement The compiled statement
*/
void bindTo(SupportSQLiteProgram statement);
/**
* Returns the number of arguments in this query. This is equal to the number of placeholders
* in the query string. See: https://www.sqlite.org/c3ref/bind_blob.html for details.
*
* @return The number of arguments in the query.
*/
int getArgCount();
}

View File

@ -0,0 +1,190 @@
/*
* Copyright (C) 2017 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.arch.persistence.db;
import java.util.regex.Pattern;
/**
* A simple query builder to create SQL SELECT queries.
*/
@SuppressWarnings("unused")
public final class SupportSQLiteQueryBuilder {
private static final Pattern sLimitPattern =
Pattern.compile("\\s*\\d+\\s*(,\\s*\\d+\\s*)?");
private final String mTable;
private boolean mDistinct = false;
private String[] mColumns = null;
private String mSelection;
private Object[] mBindArgs;
private String mGroupBy = null;
private String mHaving = null;
private String mOrderBy = null;
private String mLimit = null;
private SupportSQLiteQueryBuilder(String table) {
mTable = table;
}
/**
* Creates a query for the given table name.
*
* @param tableName The table name(s) to query.
* @return A builder to create a query.
*/
public static SupportSQLiteQueryBuilder builder(String tableName) {
return new SupportSQLiteQueryBuilder(tableName);
}
private static void appendClause(StringBuilder s, String name, String clause) {
if (!isEmpty(clause)) {
s.append(name);
s.append(clause);
}
}
/**
* Add the names that are non-null in columns to s, separating
* them with commas.
*/
private static void appendColumns(StringBuilder s, String[] columns) {
int n = columns.length;
for (int i = 0; i < n; i++) {
String column = columns[i];
if (i > 0) {
s.append(", ");
}
s.append(column);
}
s.append(' ');
}
private static boolean isEmpty(String input) {
return input == null || input.length() == 0;
}
/**
* Adds DISTINCT keyword to the query.
*
* @return this
*/
public SupportSQLiteQueryBuilder distinct() {
mDistinct = true;
return this;
}
/**
* Sets the given list of columns as the columns that will be returned.
*
* @param columns The list of column names that should be returned.
* @return this
*/
public SupportSQLiteQueryBuilder columns(String[] columns) {
mColumns = columns;
return this;
}
/**
* Sets the arguments for the WHERE clause.
*
* @param selection The list of selection columns
* @param bindArgs The list of bind arguments to match against these columns
* @return this
*/
public SupportSQLiteQueryBuilder selection(String selection, Object[] bindArgs) {
mSelection = selection;
mBindArgs = bindArgs;
return this;
}
/**
* Adds a GROUP BY statement.
*
* @param groupBy The value of the GROUP BY statement.
* @return this
*/
@SuppressWarnings("WeakerAccess")
public SupportSQLiteQueryBuilder groupBy(String groupBy) {
mGroupBy = groupBy;
return this;
}
/**
* Adds a HAVING statement. You must also provide {@link #groupBy(String)} for this to work.
*
* @param having The having clause.
* @return this
*/
public SupportSQLiteQueryBuilder having(String having) {
mHaving = having;
return this;
}
/**
* Adds an ORDER BY statement.
*
* @param orderBy The order clause.
* @return this
*/
public SupportSQLiteQueryBuilder orderBy(String orderBy) {
mOrderBy = orderBy;
return this;
}
/**
* Adds a LIMIT statement.
*
* @param limit The limit value.
* @return this
*/
public SupportSQLiteQueryBuilder limit(String limit) {
if (!isEmpty(limit) && !sLimitPattern.matcher(limit).matches()) {
throw new IllegalArgumentException("invalid LIMIT clauses:" + limit);
}
mLimit = limit;
return this;
}
/**
* Creates the {@link SupportSQLiteQuery} that can be passed into
* {@link SupportSQLiteDatabase#query(SupportSQLiteQuery)}.
*
* @return a new query
*/
public SupportSQLiteQuery create() {
if (isEmpty(mGroupBy) && !isEmpty(mHaving)) {
throw new IllegalArgumentException(
"HAVING clauses are only permitted when using a groupBy clause");
}
StringBuilder query = new StringBuilder(120);
query.append("SELECT ");
if (mDistinct) {
query.append("DISTINCT ");
}
if (mColumns != null && mColumns.length != 0) {
appendColumns(query, mColumns);
} else {
query.append(" * ");
}
query.append(" FROM ");
query.append(mTable);
appendClause(query, " WHERE ", mSelection);
appendClause(query, " GROUP BY ", mGroupBy);
appendClause(query, " HAVING ", mHaving);
appendClause(query, " ORDER BY ", mOrderBy);
appendClause(query, " LIMIT ", mLimit);
return new SimpleSQLiteQuery(query.toString(), mBindArgs);
}
}

View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2016 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.arch.persistence.db;
/**
* An interface to map the behavior of {@link android.database.sqlite.SQLiteStatement}.
*/
@SuppressWarnings("unused")
public interface SupportSQLiteStatement extends SupportSQLiteProgram {
/**
* Execute this SQL statement, if it is not a SELECT / INSERT / DELETE / UPDATE, for example
* CREATE / DROP table, view, trigger, index etc.
*
* @throws android.database.SQLException If the SQL string is invalid for
* some reason
*/
void execute();
/**
* Execute this SQL statement, if the the number of rows affected by execution of this SQL
* statement is of any importance to the caller - for example, UPDATE / DELETE SQL statements.
*
* @return the number of rows affected by this SQL statement execution.
* @throws android.database.SQLException If the SQL string is invalid for
* some reason
*/
int executeUpdateDelete();
/**
* Execute this SQL statement and return the ID of the row inserted due to this call.
* The SQL statement should be an INSERT for this to be a useful call.
*
* @return the row ID of the last row inserted, if this insert is successful. -1 otherwise.
* @throws android.database.SQLException If the SQL string is invalid for
* some reason
*/
long executeInsert();
/**
* Execute a statement that returns a 1 by 1 table with a numeric value.
* For example, SELECT COUNT(*) FROM table;
*
* @return The result of the query.
* @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
*/
long simpleQueryForLong();
/**
* Execute a statement that returns a 1 by 1 table with a text value.
* For example, SELECT COUNT(*) FROM table;
*
* @return The result of the query.
* @throws android.database.sqlite.SQLiteDoneException if the query returns zero rows
*/
String simpleQueryForString();
}

View File

@ -0,0 +1,307 @@
/*
* Copyright (C) 2016 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.arch.persistence.db.framework;
import android.arch.persistence.db.SimpleSQLiteQuery;
import android.arch.persistence.db.SupportSQLiteDatabase;
import android.arch.persistence.db.SupportSQLiteQuery;
import android.arch.persistence.db.SupportSQLiteStatement;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.*;
import android.os.Build;
import android.os.CancellationSignal;
import android.util.Pair;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import static android.text.TextUtils.isEmpty;
/**
* Delegates all calls to an implementation of {@link SQLiteDatabase}.
*/
@SuppressWarnings("unused")
class FrameworkSQLiteDatabase implements SupportSQLiteDatabase {
private static final String[] CONFLICT_VALUES = new String[]
{"", " OR ROLLBACK ", " OR ABORT ", " OR FAIL ", " OR IGNORE ", " OR REPLACE "};
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private final SQLiteDatabase mDelegate;
/**
* Creates a wrapper around {@link SQLiteDatabase}.
*
* @param delegate The delegate to receive all calls.
*/
FrameworkSQLiteDatabase(SQLiteDatabase delegate) {
mDelegate = delegate;
}
@Override
public SupportSQLiteStatement compileStatement(String sql) {
return new FrameworkSQLiteStatement(mDelegate.compileStatement(sql));
}
@Override
public void beginTransaction() {
mDelegate.beginTransaction();
}
@Override
public void beginTransactionNonExclusive() {
mDelegate.beginTransactionNonExclusive();
}
@Override
public void beginTransactionWithListener(SQLiteTransactionListener transactionListener) {
mDelegate.beginTransactionWithListener(transactionListener);
}
@Override
public void beginTransactionWithListenerNonExclusive(
SQLiteTransactionListener transactionListener) {
mDelegate.beginTransactionWithListenerNonExclusive(transactionListener);
}
@Override
public void endTransaction() {
mDelegate.endTransaction();
}
@Override
public void setTransactionSuccessful() {
mDelegate.setTransactionSuccessful();
}
@Override
public boolean inTransaction() {
return mDelegate.inTransaction();
}
@Override
public boolean isDbLockedByCurrentThread() {
return mDelegate.isDbLockedByCurrentThread();
}
@Override
public boolean yieldIfContendedSafely() {
return mDelegate.yieldIfContendedSafely();
}
@Override
public boolean yieldIfContendedSafely(long sleepAfterYieldDelay) {
return mDelegate.yieldIfContendedSafely(sleepAfterYieldDelay);
}
@Override
public int getVersion() {
return mDelegate.getVersion();
}
@Override
public void setVersion(int version) {
mDelegate.setVersion(version);
}
@Override
public long getMaximumSize() {
return mDelegate.getMaximumSize();
}
@Override
public long setMaximumSize(long numBytes) {
return mDelegate.setMaximumSize(numBytes);
}
@Override
public long getPageSize() {
return mDelegate.getPageSize();
}
@Override
public void setPageSize(long numBytes) {
mDelegate.setPageSize(numBytes);
}
@Override
public Cursor query(String query) {
return query(new SimpleSQLiteQuery(query));
}
@Override
public Cursor query(String query, Object[] bindArgs) {
return query(new SimpleSQLiteQuery(query, bindArgs));
}
@Override
public Cursor query(final SupportSQLiteQuery supportQuery) {
return mDelegate.rawQueryWithFactory(new SQLiteDatabase.CursorFactory() {
@Override
public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery,
String editTable, SQLiteQuery query) {
supportQuery.bindTo(new FrameworkSQLiteProgram(query));
return new SQLiteCursor(masterQuery, editTable, query);
}
}, supportQuery.getSql(), EMPTY_STRING_ARRAY, null);
}
@Override
@androidx.annotation.RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public Cursor query(final SupportSQLiteQuery supportQuery,
CancellationSignal cancellationSignal) {
return mDelegate.rawQueryWithFactory(new SQLiteDatabase.CursorFactory() {
@Override
public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery,
String editTable, SQLiteQuery query) {
supportQuery.bindTo(new FrameworkSQLiteProgram(query));
return new SQLiteCursor(masterQuery, editTable, query);
}
}, supportQuery.getSql(), EMPTY_STRING_ARRAY, null, cancellationSignal);
}
@Override
public long insert(String table, int conflictAlgorithm, ContentValues values)
throws SQLException {
return mDelegate.insertWithOnConflict(table, null, values,
conflictAlgorithm);
}
@Override
public int delete(String table, String whereClause, Object[] whereArgs) {
String query = "DELETE FROM " + table
+ (isEmpty(whereClause) ? "" : " WHERE " + whereClause);
SupportSQLiteStatement statement = compileStatement(query);
SimpleSQLiteQuery.bind(statement, whereArgs);
return statement.executeUpdateDelete();
}
@Override
public int update(String table, int conflictAlgorithm, ContentValues values, String whereClause,
Object[] whereArgs) {
// taken from SQLiteDatabase class.
if (values == null || values.size() == 0) {
throw new IllegalArgumentException("Empty values");
}
StringBuilder sql = new StringBuilder(120);
sql.append("UPDATE ");
sql.append(CONFLICT_VALUES[conflictAlgorithm]);
sql.append(table);
sql.append(" SET ");
// move all bind args to one array
int setValuesSize = values.size();
int bindArgsSize = (whereArgs == null) ? setValuesSize : (setValuesSize + whereArgs.length);
Object[] bindArgs = new Object[bindArgsSize];
int i = 0;
for (String colName : values.keySet()) {
sql.append((i > 0) ? "," : "");
sql.append(colName);
bindArgs[i++] = values.get(colName);
sql.append("=?");
}
if (whereArgs != null) {
for (i = setValuesSize; i < bindArgsSize; i++) {
bindArgs[i] = whereArgs[i - setValuesSize];
}
}
if (!isEmpty(whereClause)) {
sql.append(" WHERE ");
sql.append(whereClause);
}
SupportSQLiteStatement stmt = compileStatement(sql.toString());
SimpleSQLiteQuery.bind(stmt, bindArgs);
return stmt.executeUpdateDelete();
}
@Override
public void execSQL(String sql) throws SQLException {
mDelegate.execSQL(sql);
}
@Override
public void execSQL(String sql, Object[] bindArgs) throws SQLException {
mDelegate.execSQL(sql, bindArgs);
}
@Override
public boolean isReadOnly() {
return mDelegate.isReadOnly();
}
@Override
public boolean isOpen() {
return mDelegate.isOpen();
}
@Override
public boolean needUpgrade(int newVersion) {
return mDelegate.needUpgrade(newVersion);
}
@Override
public String getPath() {
return mDelegate.getPath();
}
@Override
public void setLocale(Locale locale) {
mDelegate.setLocale(locale);
}
@Override
public void setMaxSqlCacheSize(int cacheSize) {
mDelegate.setMaxSqlCacheSize(cacheSize);
}
@Override
@androidx.annotation.RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public void setForeignKeyConstraintsEnabled(boolean enable) {
mDelegate.setForeignKeyConstraintsEnabled(enable);
}
@Override
public boolean enableWriteAheadLogging() {
return mDelegate.enableWriteAheadLogging();
}
@Override
@androidx.annotation.RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public void disableWriteAheadLogging() {
mDelegate.disableWriteAheadLogging();
}
@Override
@androidx.annotation.RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public boolean isWriteAheadLoggingEnabled() {
return mDelegate.isWriteAheadLoggingEnabled();
}
@Override
public List<Pair<String, String>> getAttachedDbs() {
return mDelegate.getAttachedDbs();
}
@Override
public boolean isDatabaseIntegrityOk() {
return mDelegate.isDatabaseIntegrityOk();
}
@Override
public void close() throws IOException {
mDelegate.close();
}
}

View File

@ -0,0 +1,159 @@
/*
* Copyright (C) 2016 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.arch.persistence.db.framework;
import android.arch.persistence.db.SupportSQLiteDatabase;
import android.arch.persistence.db.SupportSQLiteOpenHelper;
import android.content.Context;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Build;
class FrameworkSQLiteOpenHelper implements SupportSQLiteOpenHelper {
private final OpenHelper mDelegate;
FrameworkSQLiteOpenHelper(Context context, String name,
Callback callback) {
mDelegate = createDelegate(context, name, callback);
}
private OpenHelper createDelegate(Context context, String name, Callback callback) {
final FrameworkSQLiteDatabase[] dbRef = new FrameworkSQLiteDatabase[1];
return new OpenHelper(context, name, dbRef, callback);
}
@Override
public String getDatabaseName() {
return mDelegate.getDatabaseName();
}
@Override
@androidx.annotation.RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public void setWriteAheadLoggingEnabled(boolean enabled) {
mDelegate.setWriteAheadLoggingEnabled(enabled);
}
@Override
public SupportSQLiteDatabase getWritableDatabase() {
return mDelegate.getWritableSupportDatabase();
}
@Override
public SupportSQLiteDatabase getReadableDatabase() {
return mDelegate.getReadableSupportDatabase();
}
@Override
public void close() {
mDelegate.close();
}
static class OpenHelper extends SQLiteOpenHelper {
/**
* This is used as an Object reference so that we can access the wrapped database inside
* the constructor. SQLiteOpenHelper requires the error handler to be passed in the
* constructor.
*/
final FrameworkSQLiteDatabase[] mDbRef;
final Callback mCallback;
// see b/78359448
private boolean mMigrated;
OpenHelper(Context context, String name, final FrameworkSQLiteDatabase[] dbRef,
final Callback callback) {
super(context, name, null, callback.version,
new DatabaseErrorHandler() {
@Override
public void onCorruption(SQLiteDatabase dbObj) {
FrameworkSQLiteDatabase db = dbRef[0];
if (db != null) {
callback.onCorruption(db);
}
}
});
mCallback = callback;
mDbRef = dbRef;
}
synchronized SupportSQLiteDatabase getWritableSupportDatabase() {
mMigrated = false;
SQLiteDatabase db = super.getWritableDatabase();
if (mMigrated) {
// there might be a connection w/ stale structure, we should re-open.
close();
return getWritableSupportDatabase();
}
return getWrappedDb(db);
}
synchronized SupportSQLiteDatabase getReadableSupportDatabase() {
mMigrated = false;
SQLiteDatabase db = super.getReadableDatabase();
if (mMigrated) {
// there might be a connection w/ stale structure, we should re-open.
close();
return getReadableSupportDatabase();
}
return getWrappedDb(db);
}
FrameworkSQLiteDatabase getWrappedDb(SQLiteDatabase sqLiteDatabase) {
FrameworkSQLiteDatabase dbRef = mDbRef[0];
if (dbRef == null) {
dbRef = new FrameworkSQLiteDatabase(sqLiteDatabase);
mDbRef[0] = dbRef;
}
return mDbRef[0];
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
mCallback.onCreate(getWrappedDb(sqLiteDatabase));
}
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
mMigrated = true;
mCallback.onUpgrade(getWrappedDb(sqLiteDatabase), oldVersion, newVersion);
}
@Override
public void onConfigure(SQLiteDatabase db) {
mCallback.onConfigure(getWrappedDb(db));
}
@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
mMigrated = true;
mCallback.onDowngrade(getWrappedDb(db), oldVersion, newVersion);
}
@Override
public void onOpen(SQLiteDatabase db) {
if (!mMigrated) {
// if we've migrated, we'll re-open the db so we should not call the callback.
mCallback.onOpen(getWrappedDb(db));
}
}
@Override
public synchronized void close() {
super.close();
mDbRef[0] = null;
}
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright (C) 2016 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.arch.persistence.db.framework;
import android.arch.persistence.db.SupportSQLiteOpenHelper;
/**
* Implements {@link SupportSQLiteOpenHelper.Factory} using the SQLite implementation in the
* framework.
*/
@SuppressWarnings("unused")
public final class FrameworkSQLiteOpenHelperFactory implements SupportSQLiteOpenHelper.Factory {
@Override
public SupportSQLiteOpenHelper create(SupportSQLiteOpenHelper.Configuration configuration) {
return new FrameworkSQLiteOpenHelper(
configuration.context, configuration.name, configuration.callback);
}
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2017 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.arch.persistence.db.framework;
import android.arch.persistence.db.SupportSQLiteProgram;
import android.database.sqlite.SQLiteProgram;
/**
* An wrapper around {@link SQLiteProgram} to implement {@link SupportSQLiteProgram} API.
*/
class FrameworkSQLiteProgram implements SupportSQLiteProgram {
private final SQLiteProgram mDelegate;
FrameworkSQLiteProgram(SQLiteProgram delegate) {
mDelegate = delegate;
}
@Override
public void bindNull(int index) {
mDelegate.bindNull(index);
}
@Override
public void bindLong(int index, long value) {
mDelegate.bindLong(index, value);
}
@Override
public void bindDouble(int index, double value) {
mDelegate.bindDouble(index, value);
}
@Override
public void bindString(int index, String value) {
mDelegate.bindString(index, value);
}
@Override
public void bindBlob(int index, byte[] value) {
mDelegate.bindBlob(index, value);
}
@Override
public void clearBindings() {
mDelegate.clearBindings();
}
@Override
public void close() {
mDelegate.close();
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2016 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.arch.persistence.db.framework;
import android.arch.persistence.db.SupportSQLiteStatement;
import android.database.sqlite.SQLiteStatement;
/**
* Delegates all calls to a {@link SQLiteStatement}.
*/
class FrameworkSQLiteStatement extends FrameworkSQLiteProgram implements SupportSQLiteStatement {
private final SQLiteStatement mDelegate;
/**
* Creates a wrapper around a framework {@link SQLiteStatement}.
*
* @param delegate The SQLiteStatement to delegate calls to.
*/
FrameworkSQLiteStatement(SQLiteStatement delegate) {
super(delegate);
mDelegate = delegate;
}
@Override
public void execute() {
mDelegate.execute();
}
@Override
public int executeUpdateDelete() {
return mDelegate.executeUpdateDelete();
}
@Override
public long executeInsert() {
return mDelegate.executeInsert();
}
@Override
public long simpleQueryForLong() {
return mDelegate.simpleQueryForLong();
}
@Override
public String simpleQueryForString() {
return mDelegate.simpleQueryForString();
}
}

View File

@ -0,0 +1,64 @@
/*
* 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 android.content.res.Configuration;
/**
* The set of callback APIs that are common to all application components
* ({@link android.app.Activity}, {@link android.app.Service},
* {@link ContentProvider}, and {@link android.app.Application}).
*
* <p class="note"><strong>Note:</strong> You should also implement the {@link
* ComponentCallbacks2} interface, which provides the {@link
* ComponentCallbacks2#onTrimMemory} callback to help your app manage its memory usage more
* effectively.</p>
*/
public interface ComponentCallbacks {
/**
* Called by the system when the device configuration changes while your
* component is running. Note that, unlike activities, other components
* are never restarted when a configuration changes: they must always deal
* with the results of the change, such as by re-retrieving resources.
*
* <p>At the time that this function has been called, your Resources
* object will have been updated to return resource values matching the
* new configuration.
*
* <p>For more information, read <a href="{@docRoot}guide/topics/resources/runtime-changes.html"
* >Handling Runtime Changes</a>.
*
* @param newConfig The new device configuration.
*/
void onConfigurationChanged(Configuration newConfig);
/**
* This is called when the overall system is running low on memory, and
* actively running processes should trim their memory usage. While
* the exact point at which this will be called is not defined, generally
* it will happen when all background process have been killed.
* That is, before reaching the point of killing processes hosting
* service and foreground UI that we would like to avoid killing.
*
* <p>You should implement this method to release
* any caches or other unnecessary resources you may be holding on to.
* The system will perform a garbage collection for you after returning from this method.
* <p>Preferably, you should implement {@link ComponentCallbacks2#onTrimMemory} from
* {@link ComponentCallbacks2} to incrementally unload your resources based on various
* levels of memory demands. That API is available for API level 14 and higher, so you should
* only use this {@link #onLowMemory} method as a fallback for older versions, which can be
* treated the same as {@link ComponentCallbacks2#onTrimMemory} with the {@link
* ComponentCallbacks2#TRIM_MEMORY_COMPLETE} level.</p>
*/
void onLowMemory();
}

View File

@ -0,0 +1,168 @@
/*
* 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 android.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Extended {@link ComponentCallbacks} interface with a new callback for
* finer-grained memory management. This interface is available in all application components
* ({@link android.app.Activity}, {@link android.app.Service},
* {@link ContentProvider}, and {@link android.app.Application}).
*
* <p>You should implement {@link #onTrimMemory} to incrementally release memory based on current
* system constraints. Using this callback to release your resources helps provide a more
* responsive system overall, but also directly benefits the user experience for
* your app by allowing the system to keep your process alive longer. That is,
* if you <em>don't</em> trim your resources based on memory levels defined by this callback,
* the system is more likely to kill your process while it is cached in the least-recently used
* (LRU) list, thus requiring your app to restart and restore all state when the user returns to it.
*
* <p>The values provided by {@link #onTrimMemory} do not represent a single linear progression of
* memory limits, but provide you different types of clues about memory availability:</p>
* <ul>
* <li>When your app is running:
* <ol>
* <li>{@link #TRIM_MEMORY_RUNNING_MODERATE} <br>The device is beginning to run low on memory.
* Your app is running and not killable.
* <li>{@link #TRIM_MEMORY_RUNNING_LOW} <br>The device is running much lower on memory.
* Your app is running and not killable, but please release unused resources to improve system
* performance (which directly impacts your app's performance).
* <li>{@link #TRIM_MEMORY_RUNNING_CRITICAL} <br>The device is running extremely low on memory.
* Your app is not yet considered a killable process, but the system will begin killing
* background processes if apps do not release resources, so you should release non-critical
* resources now to prevent performance degradation.
* </ol>
* </li>
* <li>When your app's visibility changes:
* <ol>
* <li>{@link #TRIM_MEMORY_UI_HIDDEN} <br>Your app's UI is no longer visible, so this is a good
* time to release large resources that are used only by your UI.
* </ol>
* </li>
* <li>When your app's process resides in the background LRU list:
* <ol>
* <li>{@link #TRIM_MEMORY_BACKGROUND} <br>The system is running low on memory and your process is
* near the beginning of the LRU list. Although your app process is not at a high risk of being
* killed, the system may already be killing processes in the LRU list, so you should release
* resources that are easy to recover so your process will remain in the list and resume
* quickly when the user returns to your app.
* <li>{@link #TRIM_MEMORY_MODERATE} <br>The system is running low on memory and your process is
* near the middle of the LRU list. If the system becomes further constrained for memory, there's a
* chance your process will be killed.
* <li>{@link #TRIM_MEMORY_COMPLETE} <br>The system is running low on memory and your process is
* one of the first to be killed if the system does not recover memory now. You should release
* absolutely everything that's not critical to resuming your app state.
* <p>To support API levels lower than 14, you can use the {@link #onLowMemory} method as a
* fallback that's roughly equivalent to the {@link ComponentCallbacks2#TRIM_MEMORY_COMPLETE} level.
* </li>
* </ol>
* <p class="note"><strong>Note:</strong> When the system begins
* killing processes in the LRU list, although it primarily works bottom-up, it does give some
* consideration to which processes are consuming more memory and will thus provide more gains in
* memory if killed. So the less memory you consume while in the LRU list overall, the better
* your chances are to remain in the list and be able to quickly resume.</p>
* </li>
* </ul>
* <p>More information about the different stages of a process lifecycle (such as what it means
* to be placed in the background LRU list) is provided in the <a
* href="{@docRoot}guide/components/processes-and-threads.html#Lifecycle">Processes and Threads</a>
* document.
*/
public interface ComponentCallbacks2 extends ComponentCallbacks {
/** @hide */
@IntDef(prefix = { "TRIM_MEMORY_" }, value = {
TRIM_MEMORY_COMPLETE,
TRIM_MEMORY_MODERATE,
TRIM_MEMORY_BACKGROUND,
TRIM_MEMORY_UI_HIDDEN,
TRIM_MEMORY_RUNNING_CRITICAL,
TRIM_MEMORY_RUNNING_LOW,
TRIM_MEMORY_RUNNING_MODERATE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface TrimMemoryLevel {}
/**
* Level for {@link #onTrimMemory(int)}: the process is nearing the end
* of the background LRU list, and if more memory isn't found soon it will
* be killed.
*/
static final int TRIM_MEMORY_COMPLETE = 80;
/**
* Level for {@link #onTrimMemory(int)}: the process is around the middle
* of the background LRU list; freeing memory can help the system keep
* other processes running later in the list for better overall performance.
*/
static final int TRIM_MEMORY_MODERATE = 60;
/**
* Level for {@link #onTrimMemory(int)}: the process has gone on to the
* LRU list. This is a good opportunity to clean up resources that can
* efficiently and quickly be re-built if the user returns to the app.
*/
static final int TRIM_MEMORY_BACKGROUND = 40;
/**
* Level for {@link #onTrimMemory(int)}: the process had been showing
* a user interface, and is no longer doing so. Large allocations with
* the UI should be released at this point to allow memory to be better
* managed.
*/
static final int TRIM_MEMORY_UI_HIDDEN = 20;
/**
* Level for {@link #onTrimMemory(int)}: the process is not an expendable
* background process, but the device is running extremely low on memory
* and is about to not be able to keep any background processes running.
* Your running process should free up as many non-critical resources as it
* can to allow that memory to be used elsewhere. The next thing that
* will happen after this is {@link #onLowMemory()} called to report that
* nothing at all can be kept in the background, a situation that can start
* to notably impact the user.
*/
static final int TRIM_MEMORY_RUNNING_CRITICAL = 15;
/**
* Level for {@link #onTrimMemory(int)}: the process is not an expendable
* background process, but the device is running low on memory.
* Your running process should free up unneeded resources to allow that
* memory to be used elsewhere.
*/
static final int TRIM_MEMORY_RUNNING_LOW = 10;
/**
* Level for {@link #onTrimMemory(int)}: the process is not an expendable
* background process, but the device is running moderately low on memory.
* Your running process may want to release some unneeded resources for
* use elsewhere.
*/
static final int TRIM_MEMORY_RUNNING_MODERATE = 5;
/**
* Called when the operating system has determined that it is a good
* time for a process to trim unneeded memory from its process. This will
* happen for example when it goes in the background and there is not enough
* memory to keep as many background processes running as desired. You
* should never compare to exact values of the level, since new intermediate
* values may be added -- you will typically want to compare if the value
* is greater or equal to a level you are interested in.
*
* <p>To retrieve the processes current trim level at any point, you can
* use {@link android.app.ActivityManager#getMyMemoryState
* ActivityManager.getMyMemoryState(RunningAppProcessInfo)}.
*
* @param level The context of the trim, giving a hint of the amount of
* trimming the application may like to perform.
*/
void onTrimMemory(@TrimMemoryLevel int level);
}

View File

@ -0,0 +1,362 @@
/*
* 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 android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import java.io.PrintWriter;
import java.lang.Comparable;
/**
* 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 implements Parcelable, Cloneable, Comparable<ComponentName> {
private final String mPackage;
private final String mClass;
/**
* Create a new component identifier where the class name may be specified
* as either absolute or relative to the containing package.
*
* <p>Relative package names begin with a <code>'.'</code> character. For a package
* <code>"com.example"</code> and class name <code>".app.MyActivity"</code> this method
* will return a ComponentName with the package <code>"com.example"</code>and class name
* <code>"com.example.app.MyActivity"</code>. Fully qualified class names are also
* permitted.</p>
*
* @param pkg the name of the package the component exists in
* @param cls the name of the class inside of <var>pkg</var> that implements
* the component
* @return the new ComponentName
*/
public static ComponentName createRelative(String pkg, String cls) {
if (TextUtils.isEmpty(cls)) {
throw new IllegalArgumentException("class name cannot be empty");
}
final String fullName;
if (cls.charAt(0) == '.') {
// Relative to the package. Prepend the package name.
fullName = pkg + cls;
} else {
// Fully qualified package name.
fullName = cls;
}
return new ComponentName(pkg, fullName);
}
/**
* Create a new component identifier where the class name may be specified
* as either absolute or relative to the containing package.
*
* <p>Relative package names begin with a <code>'.'</code> character. For a package
* <code>"com.example"</code> and class name <code>".app.MyActivity"</code> this method
* will return a ComponentName with the package <code>"com.example"</code>and class name
* <code>"com.example.app.MyActivity"</code>. Fully qualified class names are also
* permitted.</p>
*
* @param pkg a Context for the package implementing the component
* @param cls the name of the class inside of <var>pkg</var> that implements
* the component
* @return the new ComponentName
*/
public static ComponentName createRelative(Context pkg, String cls) {
return createRelative(pkg.getPackageName(), cls);
}
/**
* Create a new component identifier.
*
* @param pkg The name of the package that the component exists in. Can
* not be null.
* @param cls The name of the class inside of <var>pkg</var> that
* implements the component. Can not be null.
*/
public ComponentName(String pkg, String cls) {
if (pkg == null) throw new NullPointerException("package name is null");
if (cls == null) throw new NullPointerException("class name is null");
mPackage = pkg;
mClass = cls;
}
/**
* Create a new component identifier from a Context and class name.
*
* @param pkg A Context for the package implementing the component,
* from which the actual package name will be retrieved.
* @param cls The name of the class inside of <var>pkg</var> that
* implements the component.
*/
public ComponentName(Context pkg, String cls) {
if (cls == null) throw new NullPointerException("class name is null");
mPackage = pkg.getPackageName();
mClass = cls;
}
/**
* Create a new component identifier from a Context and Class object.
*
* @param pkg A Context for the package implementing the component, from
* which the actual package name will be retrieved.
* @param cls The Class object of the desired component, from which the
* actual class name will be retrieved.
*/
public ComponentName(Context pkg, Class<?> cls) {
mPackage = pkg.getPackageName();
mClass = cls.getName();
}
public ComponentName clone() {
return new ComponentName(mPackage, mClass);
}
/**
* Return the package name of this component.
*/
public String getPackageName() {
return mPackage;
}
/**
* Return the class name of this component.
*/
public String getClassName() {
return mClass;
}
/**
* Return the class name, either fully qualified or in a shortened form
* (with a leading '.') if it is a suffix of the package.
*/
public String getShortClassName() {
if (mClass.startsWith(mPackage)) {
int PN = mPackage.length();
int CN = mClass.length();
if (CN > PN && mClass.charAt(PN) == '.') {
return mClass.substring(PN, CN);
}
}
return mClass;
}
private static void appendShortClassName(StringBuilder sb, String packageName,
String className) {
if (className.startsWith(packageName)) {
int PN = packageName.length();
int CN = className.length();
if (CN > PN && className.charAt(PN) == '.') {
sb.append(className, PN, CN);
return;
}
}
sb.append(className);
}
private static void printShortClassName(PrintWriter pw, String packageName,
String className) {
if (className.startsWith(packageName)) {
int PN = packageName.length();
int CN = className.length();
if (CN > PN && className.charAt(PN) == '.') {
pw.write(className, PN, CN-PN);
return;
}
}
pw.print(className);
}
/**
* Return a String that unambiguously describes both the package and
* class names contained in the ComponentName. You can later recover
* the ComponentName from this string through
* {@link #unflattenFromString(String)}.
*
* @return Returns a new String holding the package and class names. This
* is represented as the package name, concatenated with a '/' and then the
* class name.
*
* @see #unflattenFromString(String)
*/
public String flattenToString() {
return mPackage + "/" + mClass;
}
/**
* The same as {@link #flattenToString()}, but abbreviates the class
* name if it is a suffix of the package. The result can still be used
* with {@link #unflattenFromString(String)}.
*
* @return Returns a new String holding the package and class names. This
* is represented as the package name, concatenated with a '/' and then the
* class name.
*
* @see #unflattenFromString(String)
*/
public String flattenToShortString() {
StringBuilder sb = new StringBuilder(mPackage.length() + mClass.length());
appendShortString(sb, mPackage, mClass);
return sb.toString();
}
/** @hide */
public void appendShortString(StringBuilder sb) {
appendShortString(sb, mPackage, mClass);
}
/** @hide */
public static void appendShortString(StringBuilder sb, String packageName, String className) {
sb.append(packageName).append('/');
appendShortClassName(sb, packageName, className);
}
/** @hide */
public static void printShortString(PrintWriter pw, String packageName, String className) {
pw.print(packageName);
pw.print('/');
printShortClassName(pw, packageName, className);
}
/**
* Recover a ComponentName from a String that was previously created with
* {@link #flattenToString()}. It splits the string at the first '/',
* taking the part before as the package name and the part after as the
* class name. As a special convenience (to use, for example, when
* parsing component names on the command line), if the '/' is immediately
* followed by a '.' then the final class name will be the concatenation
* of the package name with the string following the '/'. Thus
* "com.foo/.Blah" becomes package="com.foo" class="com.foo.Blah".
*
* @param str The String that was returned by flattenToString().
* @return Returns a new ComponentName containing the package and class
* names that were encoded in <var>str</var>
*
* @see #flattenToString()
*/
public static ComponentName unflattenFromString(String str) {
int sep = str.indexOf('/');
if (sep < 0 || (sep+1) >= str.length()) {
return null;
}
String pkg = str.substring(0, sep);
String cls = str.substring(sep+1);
if (cls.length() > 0 && cls.charAt(0) == '.') {
cls = pkg + cls;
}
return new ComponentName(pkg, cls);
}
/**
* Return string representation of this class without the class's name
* as a prefix.
*/
public String toShortString() {
return "{" + mPackage + "/" + mClass + "}";
}
@Override
public String toString() {
return "ComponentInfo{" + mPackage + "/" + mClass + "}";
}
@Override
public boolean equals(Object obj) {
try {
if (obj != null) {
ComponentName other = (ComponentName)obj;
// Note: no null checks, because mPackage and mClass can
// never be null.
return mPackage.equals(other.mPackage)
&& mClass.equals(other.mClass);
}
} catch (ClassCastException e) {
}
return false;
}
@Override
public int hashCode() {
return mPackage.hashCode() + mClass.hashCode();
}
public int compareTo(ComponentName that) {
int v;
v = this.mPackage.compareTo(that.mPackage);
if (v != 0) {
return v;
}
return this.mClass.compareTo(that.mClass);
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(mPackage);
out.writeString(mClass);
}
/**
* Write a ComponentName to a Parcel, handling null pointers. Must be
* read with {@link #readFromParcel(Parcel)}.
*
* @param c The ComponentName to be written.
* @param out The Parcel in which the ComponentName will be placed.
*
* @see #readFromParcel(Parcel)
*/
public static void writeToParcel(ComponentName c, Parcel out) {
if (c != null) {
c.writeToParcel(out, 0);
} else {
out.writeString(null);
}
}
/**
* Read a ComponentName from a Parcel that was previously written
* with {@link #writeToParcel(ComponentName, Parcel)}, returning either
* a null or new object as appropriate.
*
* @param in The Parcel from which to read the ComponentName
* @return Returns a new ComponentName matching the previously written
* object, or null if a null had been written.
*
* @see #writeToParcel(ComponentName, Parcel)
*/
public static ComponentName readFromParcel(Parcel in) {
String pkg = in.readString();
return pkg != null ? new ComponentName(pkg, in) : null;
}
public static final Parcelable.Creator<ComponentName> CREATOR
= new Parcelable.Creator<ComponentName>() {
public ComponentName createFromParcel(Parcel in) {
return new ComponentName(in);
}
public ComponentName[] newArray(int size) {
return new ComponentName[size];
}
};
/**
* Instantiate a new ComponentName from the data in a Parcel that was
* previously written with {@link #writeToParcel(Parcel, int)}. Note that you
* must not use this with data written by
* {@link #writeToParcel(ComponentName, Parcel)} since it is not possible
* to handle a null ComponentObject here.
*
* @param in The Parcel containing the previously written ComponentName,
* positioned at the location in the buffer where it was written.
*/
public ComponentName(Parcel in) {
mPackage = in.readString();
if (mPackage == null) throw new NullPointerException(
"package name is null");
mClass = in.readString();
if (mClass == null) throw new NullPointerException(
"class name is null");
}
private ComponentName(String pkg, Parcel in) {
mPackage = pkg;
mClass = in.readString();
}
}

View File

@ -0,0 +1,473 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* This class is used to store a set of values that the {@link ContentResolver}
* can process.
*/
public final class ContentValues implements Parcelable {
public static final String TAG = "ContentValues";
/** Holds the actual values */
private HashMap<String, Object> mValues;
/**
* Creates an empty set of values using the default initial size
*/
public ContentValues() {
// Choosing a default size of 8 based on analysis of typical
// consumption by applications.
mValues = new HashMap<String, Object>(8);
}
/**
* Creates an empty set of values using the given initial size
*
* @param size the initial size of the set of values
*/
public ContentValues(int size) {
mValues = new HashMap<String, Object>(size, 1.0f);
}
/**
* Creates a set of values copied from the given set
*
* @param from the values to copy
*/
public ContentValues(ContentValues from) {
mValues = new HashMap<String, Object>(from.mValues);
}
/**
* Creates a set of values copied from the given HashMap. This is used
* by the Parcel unmarshalling code.
*
* @param values the values to start with
* {@hide}
*/
private ContentValues(HashMap<String, Object> values) {
mValues = values;
}
@Override
public boolean equals(Object object) {
if (!(object instanceof ContentValues)) {
return false;
}
return mValues.equals(((ContentValues) object).mValues);
}
@Override
public int hashCode() {
return mValues.hashCode();
}
/**
* Adds a value to the set.
*
* @param key the name of the value to put
* @param value the data for the value to put
*/
public void put(String key, String value) {
mValues.put(key, value);
}
/**
* Adds all values from the passed in ContentValues.
*
* @param other the ContentValues from which to copy
*/
public void putAll(ContentValues other) {
mValues.putAll(other.mValues);
}
/**
* Adds a value to the set.
*
* @param key the name of the value to put
* @param value the data for the value to put
*/
public void put(String key, Byte value) {
mValues.put(key, value);
}
/**
* Adds a value to the set.
*
* @param key the name of the value to put
* @param value the data for the value to put
*/
public void put(String key, Short value) {
mValues.put(key, value);
}
/**
* Adds a value to the set.
*
* @param key the name of the value to put
* @param value the data for the value to put
*/
public void put(String key, Integer value) {
mValues.put(key, value);
}
/**
* Adds a value to the set.
*
* @param key the name of the value to put
* @param value the data for the value to put
*/
public void put(String key, Long value) {
mValues.put(key, value);
}
/**
* Adds a value to the set.
*
* @param key the name of the value to put
* @param value the data for the value to put
*/
public void put(String key, Float value) {
mValues.put(key, value);
}
/**
* Adds a value to the set.
*
* @param key the name of the value to put
* @param value the data for the value to put
*/
public void put(String key, Double value) {
mValues.put(key, value);
}
/**
* Adds a value to the set.
*
* @param key the name of the value to put
* @param value the data for the value to put
*/
public void put(String key, Boolean value) {
mValues.put(key, value);
}
/**
* Adds a value to the set.
*
* @param key the name of the value to put
* @param value the data for the value to put
*/
public void put(String key, byte[] value) {
mValues.put(key, value);
}
/**
* Adds a null value to the set.
*
* @param key the name of the value to make null
*/
public void putNull(String key) {
mValues.put(key, null);
}
/**
* Returns the number of values.
*
* @return the number of values
*/
public int size() {
return mValues.size();
}
/**
* Remove a single value.
*
* @param key the name of the value to remove
*/
public void remove(String key) {
mValues.remove(key);
}
/**
* Removes all values.
*/
public void clear() {
mValues.clear();
}
/**
* Returns true if this object has the named value.
*
* @param key the value to check for
* @return {@code true} if the value is present, {@code false} otherwise
*/
public boolean containsKey(String key) {
return mValues.containsKey(key);
}
/**
* Gets a value. Valid value types are {@link String}, {@link Boolean},
* {@link Number}, and {@code byte[]} implementations.
*
* @param key the value to get
* @return the data for the value, or {@code null} if the value is missing or if {@code null}
* was previously added with the given {@code key}
*/
public Object get(String key) {
return mValues.get(key);
}
/**
* Gets a value and converts it to a String.
*
* @param key the value to get
* @return the String for the value
*/
public String getAsString(String key) {
Object value = mValues.get(key);
return value != null ? value.toString() : null;
}
/**
* Gets a value and converts it to a Long.
*
* @param key the value to get
* @return the Long value, or {@code null} if the value is missing or cannot be converted
*/
public Long getAsLong(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).longValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Long.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Long value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Long: " + value, e);
return null;
}
}
}
/**
* Gets a value and converts it to an Integer.
*
* @param key the value to get
* @return the Integer value, or {@code null} if the value is missing or cannot be converted
*/
public Integer getAsInteger(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).intValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Integer.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Integer value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Integer: " + value, e);
return null;
}
}
}
/**
* Gets a value and converts it to a Short.
*
* @param key the value to get
* @return the Short value, or {@code null} if the value is missing or cannot be converted
*/
public Short getAsShort(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).shortValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Short.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Short value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Short: " + value, e);
return null;
}
}
}
/**
* Gets a value and converts it to a Byte.
*
* @param key the value to get
* @return the Byte value, or {@code null} if the value is missing or cannot be converted
*/
public Byte getAsByte(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).byteValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Byte.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Byte value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Byte: " + value, e);
return null;
}
}
}
/**
* Gets a value and converts it to a Double.
*
* @param key the value to get
* @return the Double value, or {@code null} if the value is missing or cannot be converted
*/
public Double getAsDouble(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).doubleValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Double.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Double value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Double: " + value, e);
return null;
}
}
}
/**
* Gets a value and converts it to a Float.
*
* @param key the value to get
* @return the Float value, or {@code null} if the value is missing or cannot be converted
*/
public Float getAsFloat(String key) {
Object value = mValues.get(key);
try {
return value != null ? ((Number) value).floatValue() : null;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
try {
return Float.valueOf(value.toString());
} catch (NumberFormatException e2) {
Log.e(TAG, "Cannot parse Float value for " + value + " at key " + key);
return null;
}
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Float: " + value, e);
return null;
}
}
}
/**
* Gets a value and converts it to a Boolean.
*
* @param key the value to get
* @return the Boolean value, or {@code null} if the value is missing or cannot be converted
*/
public Boolean getAsBoolean(String key) {
Object value = mValues.get(key);
try {
return (Boolean) value;
} catch (ClassCastException e) {
if (value instanceof CharSequence) {
return Boolean.valueOf(value.toString());
} else if (value instanceof Number) {
return ((Number) value).intValue() != 0;
} else {
Log.e(TAG, "Cannot cast value for " + key + " to a Boolean: " + value, e);
return null;
}
}
}
/**
* Gets a value that is a byte array. Note that this method will not convert
* any other types to byte arrays.
*
* @param key the value to get
* @return the {@code byte[]} value, or {@code null} is the value is missing or not a
* {@code byte[]}
*/
public byte[] getAsByteArray(String key) {
Object value = mValues.get(key);
if (value instanceof byte[]) {
return (byte[]) value;
} else {
return null;
}
}
/**
* Returns a set of all of the keys and values
*
* @return a set of all of the keys and values
*/
public Set<Map.Entry<String, Object>> valueSet() {
return mValues.entrySet();
}
/**
* Returns a set of all of the keys
*
* @return a set of all of the keys
*/
public Set<String> keySet() {
return mValues.keySet();
}
public static final Parcelable.Creator<ContentValues> CREATOR =
new Parcelable.Creator<ContentValues>() {
@SuppressWarnings({"deprecation", "unchecked"})
public ContentValues createFromParcel(Parcel in) {
// TODO - what ClassLoader should be passed to readHashMap?
HashMap<String, Object> values = in.readHashMap(null);
return new ContentValues(values);
}
public ContentValues[] newArray(int size) {
return new ContentValues[size];
}
};
public int describeContents() {
return 0;
}
@SuppressWarnings("deprecation")
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeMap(mValues);
}
/**
* Unsupported, here until we get proper bulk insert APIs.
* {@hide}
*/
@Deprecated
public void putStringArrayList(String key, ArrayList<String> value) {
mValues.put(key, value);
}
/**
* Unsupported, here until we get proper bulk insert APIs.
* {@hide}
*/
@SuppressWarnings("unchecked")
@Deprecated
public ArrayList<String> getStringArrayList(String key) {
return (ArrayList<String>) mValues.get(key);
}
/**
* Returns a string containing a concise, human-readable description of this object.
* @return a printable representation of this object.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (String name : mValues.keySet()) {
String value = getAsString(name);
if (sb.length() > 0) sb.append(" ");
sb.append(name + "=" + value);
}
return sb.toString();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,720 @@
/*
* 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 android.annotation.SystemApi;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.UserHandle;
import android.view.Display;
import android.view.DisplayAdjustments;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* 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 {
Context mBase;
public ContextWrapper(Context base) {
mBase = base;
}
/**
* Set the base context for this ContextWrapper. All calls will then be
* delegated to the base context. Throws
* IllegalStateException if a base context has already been set.
*
* @param base The new base context for this wrapper.
*/
protected void attachBaseContext(Context base) {
if (mBase != null) {
throw new IllegalStateException("Base context already set");
}
mBase = base;
}
/**
* @return the base context as set by the constructor or setBaseContext
*/
public Context getBaseContext() {
return mBase;
}
@Override
public AssetManager getAssets() {
return mBase.getAssets();
}
@Override
public Resources getResources() {
return mBase.getResources();
}
@Override
public PackageManager getPackageManager() {
return mBase.getPackageManager();
}
@Override
public ContentResolver getContentResolver() {
return mBase.getContentResolver();
}
@Override
public Looper getMainLooper() {
return mBase.getMainLooper();
}
@Override
public Context getApplicationContext() {
return mBase.getApplicationContext();
}
@Override
public void setTheme(int resid) {
mBase.setTheme(resid);
}
/** @hide */
@Override
public int getThemeResId() {
return mBase.getThemeResId();
}
@Override
public Resources.Theme getTheme() {
return mBase.getTheme();
}
@Override
public ClassLoader getClassLoader() {
return mBase.getClassLoader();
}
@Override
public String getPackageName() {
return mBase.getPackageName();
}
/** @hide */
@Override
public String getBasePackageName() {
return mBase.getBasePackageName();
}
/** @hide */
@Override
public String getOpPackageName() {
return mBase.getOpPackageName();
}
@Override
public ApplicationInfo getApplicationInfo() {
return mBase.getApplicationInfo();
}
@Override
public String getPackageResourcePath() {
return mBase.getPackageResourcePath();
}
@Override
public String getPackageCodePath() {
return mBase.getPackageCodePath();
}
@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
return mBase.getSharedPreferences(name, mode);
}
/** @removed */
@Override
public SharedPreferences getSharedPreferences(File file, int mode) {
return mBase.getSharedPreferences(file, mode);
}
@Override
public boolean moveSharedPreferencesFrom(Context sourceContext, String name) {
return mBase.moveSharedPreferencesFrom(sourceContext, name);
}
@Override
public boolean deleteSharedPreferences(String name) {
return mBase.deleteSharedPreferences(name);
}
@Override
public FileInputStream openFileInput(String name)
throws FileNotFoundException {
return mBase.openFileInput(name);
}
@Override
public FileOutputStream openFileOutput(String name, int mode)
throws FileNotFoundException {
return mBase.openFileOutput(name, mode);
}
@Override
public boolean deleteFile(String name) {
return mBase.deleteFile(name);
}
@Override
public File getFileStreamPath(String name) {
return mBase.getFileStreamPath(name);
}
/** @removed */
@Override
public File getSharedPreferencesPath(String name) {
return mBase.getSharedPreferencesPath(name);
}
@Override
public String[] fileList() {
return mBase.fileList();
}
@Override
public File getDataDir() {
return mBase.getDataDir();
}
@Override
public File getFilesDir() {
return mBase.getFilesDir();
}
@Override
public File getNoBackupFilesDir() {
return mBase.getNoBackupFilesDir();
}
@Override
public File getExternalFilesDir(String type) {
return mBase.getExternalFilesDir(type);
}
@Override
public File[] getExternalFilesDirs(String type) {
return mBase.getExternalFilesDirs(type);
}
@Override
public File getObbDir() {
return mBase.getObbDir();
}
@Override
public File[] getObbDirs() {
return mBase.getObbDirs();
}
@Override
public File getCacheDir() {
return mBase.getCacheDir();
}
@Override
public File getCodeCacheDir() {
return mBase.getCodeCacheDir();
}
@Override
public File getExternalCacheDir() {
return mBase.getExternalCacheDir();
}
@Override
public File[] getExternalCacheDirs() {
return mBase.getExternalCacheDirs();
}
@Override
public File[] getExternalMediaDirs() {
return mBase.getExternalMediaDirs();
}
@Override
public File getDir(String name, int mode) {
return mBase.getDir(name, mode);
}
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {
return mBase.openOrCreateDatabase(name, mode, factory);
}
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,
DatabaseErrorHandler errorHandler) {
return mBase.openOrCreateDatabase(name, mode, factory, errorHandler);
}
@Override
public boolean moveDatabaseFrom(Context sourceContext, String name) {
return mBase.moveDatabaseFrom(sourceContext, name);
}
@Override
public boolean deleteDatabase(String name) {
return mBase.deleteDatabase(name);
}
@Override
public File getDatabasePath(String name) {
return mBase.getDatabasePath(name);
}
@Override
public String[] databaseList() {
return mBase.databaseList();
}
@Override
@Deprecated
public Drawable getWallpaper() {
return mBase.getWallpaper();
}
@Override
@Deprecated
public Drawable peekWallpaper() {
return mBase.peekWallpaper();
}
@Override
@Deprecated
public int getWallpaperDesiredMinimumWidth() {
return mBase.getWallpaperDesiredMinimumWidth();
}
@Override
@Deprecated
public int getWallpaperDesiredMinimumHeight() {
return mBase.getWallpaperDesiredMinimumHeight();
}
@Override
@Deprecated
public void setWallpaper(Bitmap bitmap) throws IOException {
mBase.setWallpaper(bitmap);
}
@Override
@Deprecated
public void setWallpaper(InputStream data) throws IOException {
mBase.setWallpaper(data);
}
@Override
@Deprecated
public void clearWallpaper() throws IOException {
mBase.clearWallpaper();
}
@Override
public void startActivity(Intent intent) {
mBase.startActivity(intent);
}
/** @hide */
@Override
public void startActivityAsUser(Intent intent, UserHandle user) {
mBase.startActivityAsUser(intent, user);
}
/** @hide **/
public void startActivityForResult(
String who, Intent intent, int requestCode, Bundle options) {
mBase.startActivityForResult(who, intent, requestCode, options);
}
/** @hide **/
public boolean canStartActivityForResult() {
return mBase.canStartActivityForResult();
}
@Override
public void startActivity(Intent intent, Bundle options) {
mBase.startActivity(intent, options);
}
/** @hide */
@Override
public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
mBase.startActivityAsUser(intent, options, user);
}
@Override
public void startActivities(Intent[] intents) {
mBase.startActivities(intents);
}
@Override
public void startActivities(Intent[] intents, Bundle options) {
mBase.startActivities(intents, options);
}
/** @hide */
@Override
public void startActivitiesAsUser(Intent[] intents, Bundle options, UserHandle userHandle) {
mBase.startActivitiesAsUser(intents, options, userHandle);
}
@Override
public void startIntentSender(IntentSender intent,
Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
throws IntentSender.SendIntentException {
mBase.startIntentSender(intent, fillInIntent, flagsMask,
flagsValues, extraFlags);
}
@Override
public void startIntentSender(IntentSender intent,
Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
Bundle options) throws IntentSender.SendIntentException {
mBase.startIntentSender(intent, fillInIntent, flagsMask,
flagsValues, extraFlags, options);
}
@Override
public void sendBroadcast(Intent intent) {
mBase.sendBroadcast(intent);
}
@Override
public void sendBroadcast(Intent intent, String receiverPermission) {
mBase.sendBroadcast(intent, receiverPermission);
}
/** @hide */
@Override
public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
mBase.sendBroadcastMultiplePermissions(intent, receiverPermissions);
}
/** @hide */
@SystemApi
@Override
public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
mBase.sendBroadcast(intent, receiverPermission, options);
}
/** @hide */
@Override
public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
mBase.sendBroadcast(intent, receiverPermission, appOp);
}
@Override
public void sendOrderedBroadcast(Intent intent,
String receiverPermission) {
mBase.sendOrderedBroadcast(intent, receiverPermission);
}
@Override
public void sendOrderedBroadcast(
Intent intent, String receiverPermission, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,
Bundle initialExtras) {
mBase.sendOrderedBroadcast(intent, receiverPermission,
resultReceiver, scheduler, initialCode,
initialData, initialExtras);
}
/** @hide */
@SystemApi
@Override
public void sendOrderedBroadcast(
Intent intent, String receiverPermission, Bundle options, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,
Bundle initialExtras) {
mBase.sendOrderedBroadcast(intent, receiverPermission,
options, resultReceiver, scheduler, initialCode,
initialData, initialExtras);
}
/** @hide */
@Override
public void sendOrderedBroadcast(
Intent intent, String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,
Bundle initialExtras) {
mBase.sendOrderedBroadcast(intent, receiverPermission, appOp,
resultReceiver, scheduler, initialCode,
initialData, initialExtras);
}
@Override
public void sendBroadcastAsUser(Intent intent, UserHandle user) {
mBase.sendBroadcastAsUser(intent, user);
}
@Override
public void sendBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission) {
mBase.sendBroadcastAsUser(intent, user, receiverPermission);
}
/** @hide */
@Override
public void sendBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission, int appOp) {
mBase.sendBroadcastAsUser(intent, user, receiverPermission, appOp);
}
@Override
public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler,
int initialCode, String initialData, Bundle initialExtras) {
mBase.sendOrderedBroadcastAsUser(intent, user, receiverPermission, resultReceiver,
scheduler, initialCode, initialData, initialExtras);
}
/** @hide */
@Override
public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
mBase.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, resultReceiver,
scheduler, initialCode, initialData, initialExtras);
}
/** @hide */
@Override
public void sendOrderedBroadcastAsUser(Intent intent, UserHandle user,
String receiverPermission, int appOp, Bundle options, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData, Bundle initialExtras) {
mBase.sendOrderedBroadcastAsUser(intent, user, receiverPermission, appOp, options,
resultReceiver, scheduler, initialCode, initialData, initialExtras);
}
@Override
@Deprecated
public void sendStickyBroadcast(Intent intent) {
mBase.sendStickyBroadcast(intent);
}
@Override
@Deprecated
public void sendStickyOrderedBroadcast(
Intent intent, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,
Bundle initialExtras) {
mBase.sendStickyOrderedBroadcast(intent,
resultReceiver, scheduler, initialCode,
initialData, initialExtras);
}
@Override
@Deprecated
public void removeStickyBroadcast(Intent intent) {
mBase.removeStickyBroadcast(intent);
}
@Override
@Deprecated
public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
mBase.sendStickyBroadcastAsUser(intent, user);
}
/** @hide */
@Override
@Deprecated
public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
mBase.sendStickyBroadcastAsUser(intent, user, options);
}
@Override
@Deprecated
public void sendStickyOrderedBroadcastAsUser(Intent intent,
UserHandle user, BroadcastReceiver resultReceiver,
Handler scheduler, int initialCode, String initialData,
Bundle initialExtras) {
mBase.sendStickyOrderedBroadcastAsUser(intent, user, resultReceiver,
scheduler, initialCode, initialData, initialExtras);
}
@Override
@Deprecated
public void removeStickyBroadcastAsUser(Intent intent, UserHandle user) {
mBase.removeStickyBroadcastAsUser(intent, user);
}
@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter) {
return mBase.registerReceiver(receiver, filter);
}
@Override
public Intent registerReceiver(
BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return mBase.registerReceiver(receiver, filter, broadcastPermission,
scheduler);
}
/** @hide */
@Override
public Intent registerReceiverAsUser(
BroadcastReceiver receiver, UserHandle user, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
return mBase.registerReceiverAsUser(receiver, user, filter, broadcastPermission,
scheduler);
}
@Override
public void unregisterReceiver(BroadcastReceiver receiver) {
mBase.unregisterReceiver(receiver);
}
@Override
public ComponentName startService(Intent service) {
return mBase.startService(service);
}
@Override
public boolean stopService(Intent name) {
return mBase.stopService(name);
}
/** @hide */
@Override
public ComponentName startServiceAsUser(Intent service, UserHandle user) {
return mBase.startServiceAsUser(service, user);
}
/** @hide */
@Override
public boolean stopServiceAsUser(Intent name, UserHandle user) {
return mBase.stopServiceAsUser(name, user);
}
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}
/** @hide */
@Override
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
UserHandle user) {
return mBase.bindServiceAsUser(service, conn, flags, user);
}
@Override
public void unbindService(ServiceConnection conn) {
mBase.unbindService(conn);
}
@Override
public boolean startInstrumentation(ComponentName className,
String profileFile, Bundle arguments) {
return mBase.startInstrumentation(className, profileFile, arguments);
}
@Override
public Object getSystemService(String name) {
return mBase.getSystemService(name);
}
@Override
public String getSystemServiceName(Class<?> serviceClass) {
return mBase.getSystemServiceName(serviceClass);
}
@Override
public int checkPermission(String permission, int pid, int uid) {
return mBase.checkPermission(permission, pid, uid);
}
/** @hide */
@Override
public int checkPermission(String permission, int pid, int uid, IBinder callerToken) {
return mBase.checkPermission(permission, pid, uid, callerToken);
}
@Override
public int checkCallingPermission(String permission) {
return mBase.checkCallingPermission(permission);
}
@Override
public int checkCallingOrSelfPermission(String permission) {
return mBase.checkCallingOrSelfPermission(permission);
}
@Override
public int checkSelfPermission(String permission) {
return mBase.checkSelfPermission(permission);
}
@Override
public void enforcePermission(
String permission, int pid, int uid, String message) {
mBase.enforcePermission(permission, pid, uid, message);
}
@Override
public void enforceCallingPermission(String permission, String message) {
mBase.enforceCallingPermission(permission, message);
}
@Override
public void enforceCallingOrSelfPermission(
String permission, String message) {
mBase.enforceCallingOrSelfPermission(permission, message);
}
@Override
public void grantUriPermission(String toPackage, Uri uri, int modeFlags) {
mBase.grantUriPermission(toPackage, uri, modeFlags);
}
@Override
public void revokeUriPermission(Uri uri, int modeFlags) {
mBase.revokeUriPermission(uri, modeFlags);
}
@Override
public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
return mBase.checkUriPermission(uri, pid, uid, modeFlags);
}
/** @hide */
@Override
public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, IBinder callerToken) {
return mBase.checkUriPermission(uri, pid, uid, modeFlags, callerToken);
}
@Override
public int checkCallingUriPermission(Uri uri, int modeFlags) {
return mBase.checkCallingUriPermission(uri, modeFlags);
}
@Override
public int checkCallingOrSelfUriPermission(Uri uri, int modeFlags) {
return mBase.checkCallingOrSelfUriPermission(uri, modeFlags);
}
@Override
public int checkUriPermission(Uri uri, String readPermission,
String writePermission, int pid, int uid, int modeFlags) {
return mBase.checkUriPermission(uri, readPermission, writePermission,
pid, uid, modeFlags);
}
@Override
public void enforceUriPermission(
Uri uri, int pid, int uid, int modeFlags, String message) {
mBase.enforceUriPermission(uri, pid, uid, modeFlags, message);
}
@Override
public void enforceCallingUriPermission(
Uri uri, int modeFlags, String message) {
mBase.enforceCallingUriPermission(uri, modeFlags, message);
}
@Override
public void enforceCallingOrSelfUriPermission(
Uri uri, int modeFlags, String message) {
mBase.enforceCallingOrSelfUriPermission(uri, modeFlags, message);
}
@Override
public void enforceUriPermission(
Uri uri, String readPermission, String writePermission,
int pid, int uid, int modeFlags, String message) {
mBase.enforceUriPermission(
uri, readPermission, writePermission, pid, uid, modeFlags,
message);
}
@Override
public Context createPackageContext(String packageName, int flags)
throws PackageManager.NameNotFoundException {
return mBase.createPackageContext(packageName, flags);
}
/** @hide */
@Override
public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)
throws PackageManager.NameNotFoundException {
return mBase.createPackageContextAsUser(packageName, flags, user);
}
/** @hide */
@Override
public Context createApplicationContext(ApplicationInfo application,
int flags) throws PackageManager.NameNotFoundException {
return mBase.createApplicationContext(application, flags);
}
/** @hide */
@Override
public int getUserId() {
return mBase.getUserId();
}
@Override
public Context createConfigurationContext(Configuration overrideConfiguration) {
return mBase.createConfigurationContext(overrideConfiguration);
}
@Override
public Context createDisplayContext(Display display) {
return mBase.createDisplayContext(display);
}
@Override
public boolean isRestricted() {
return mBase.isRestricted();
}
/** @hide */
@Override
public DisplayAdjustments getDisplayAdjustments(int displayId) {
return mBase.getDisplayAdjustments(displayId);
}
/**
* @hide
*/
@Override
public Display getDisplay() {
return mBase.getDisplay();
}
@Override
public Context createDeviceProtectedStorageContext() {
return mBase.createDeviceProtectedStorageContext();
}
/** {@hide} */
@SystemApi
@Override
public Context createCredentialProtectedStorageContext() {
return mBase.createCredentialProtectedStorageContext();
}
@Override
public boolean isDeviceProtectedStorage() {
return mBase.isDeviceProtectedStorage();
}
/** {@hide} */
@SystemApi
@Override
public boolean isCredentialProtectedStorage() {
return mBase.isCredentialProtectedStorage();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,370 @@
/*
* 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 android.annotation.Nullable;
import java.util.Map;
import java.util.Set;
/**
* Interface for accessing and modifying preference data returned by {@link
* Context#getSharedPreferences}. For any particular set of preferences,
* there is a single instance of this class that all clients share.
* Modifications to the preferences must go through an {@link Editor} object
* to ensure the preference values remain in a consistent state and control
* when they are committed to storage. Objects that are returned from the
* various <code>get</code> methods must be treated as immutable by the application.
*
* <p><em>Note: This class does not support use across multiple processes.</em>
*
* <div class="special reference">
* <h3>Developer Guides</h3>
* <p>For more information about using SharedPreferences, read the
* <a href="{@docRoot}guide/topics/data/data-storage.html#pref">Data Storage</a>
* developer guide.</p></div>
*
* @see Context#getSharedPreferences
*/
public interface SharedPreferences {
/**
* Interface definition for a callback to be invoked when a shared
* preference is changed.
*/
public interface OnSharedPreferenceChangeListener {
/**
* Called when a shared preference is changed, added, or removed. This
* may be called even if a preference is set to its existing value.
*
* <p>This callback will be run on your main thread.
*
* @param sharedPreferences The {@link SharedPreferences} that received
* the change.
* @param key The key of the preference that was changed, added, or
* removed.
*/
void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key);
}
/**
* Interface used for modifying values in a {@link SharedPreferences}
* object. All changes you make in an editor are batched, and not copied
* back to the original {@link SharedPreferences} until you call {@link #commit}
* or {@link #apply}
*/
public interface Editor {
/**
* Set a String value in the preferences editor, to be written back once
* {@link #commit} or {@link #apply} are called.
*
* @param key The name of the preference to modify.
* @param value The new value for the preference. Passing {@code null}
* for this argument is equivalent to calling {@link #remove(String)} with
* this key.
*
* @return Returns a reference to the same Editor object, so you can
* chain put calls together.
*/
Editor putString(String key, @Nullable String value);
/**
* Set a set of String values in the preferences editor, to be written
* back once {@link #commit} or {@link #apply} is called.
*
* @param key The name of the preference to modify.
* @param values The set of new values for the preference. Passing {@code null}
* for this argument is equivalent to calling {@link #remove(String)} with
* this key.
* @return Returns a reference to the same Editor object, so you can
* chain put calls together.
*/
Editor putStringSet(String key, @Nullable Set<String> values);
/**
* Set an int value in the preferences editor, to be written back once
* {@link #commit} or {@link #apply} are called.
*
* @param key The name of the preference to modify.
* @param value The new value for the preference.
*
* @return Returns a reference to the same Editor object, so you can
* chain put calls together.
*/
Editor putInt(String key, int value);
/**
* Set a long value in the preferences editor, to be written back once
* {@link #commit} or {@link #apply} are called.
*
* @param key The name of the preference to modify.
* @param value The new value for the preference.
*
* @return Returns a reference to the same Editor object, so you can
* chain put calls together.
*/
Editor putLong(String key, long value);
/**
* Set a float value in the preferences editor, to be written back once
* {@link #commit} or {@link #apply} are called.
*
* @param key The name of the preference to modify.
* @param value The new value for the preference.
*
* @return Returns a reference to the same Editor object, so you can
* chain put calls together.
*/
Editor putFloat(String key, float value);
/**
* Set a boolean value in the preferences editor, to be written back
* once {@link #commit} or {@link #apply} are called.
*
* @param key The name of the preference to modify.
* @param value The new value for the preference.
*
* @return Returns a reference to the same Editor object, so you can
* chain put calls together.
*/
Editor putBoolean(String key, boolean value);
/**
* Mark in the editor that a preference value should be removed, which
* will be done in the actual preferences once {@link #commit} is
* called.
*
* <p>Note that when committing back to the preferences, all removals
* are done first, regardless of whether you called remove before
* or after put methods on this editor.
*
* @param key The name of the preference to remove.
*
* @return Returns a reference to the same Editor object, so you can
* chain put calls together.
*/
Editor remove(String key);
/**
* Mark in the editor to remove <em>all</em> values from the
* preferences. Once commit is called, the only remaining preferences
* will be any that you have defined in this editor.
*
* <p>Note that when committing back to the preferences, the clear
* is done first, regardless of whether you called clear before
* or after put methods on this editor.
*
* @return Returns a reference to the same Editor object, so you can
* chain put calls together.
*/
Editor clear();
/**
* Commit your preferences changes back from this Editor to the
* {@link SharedPreferences} object it is editing. This atomically
* performs the requested modifications, replacing whatever is currently
* in the SharedPreferences.
*
* <p>Note that when two editors are modifying preferences at the same
* time, the last one to call commit wins.
*
* <p>If you don't care about the return value and you're
* using this from your application's main thread, consider
* using {@link #apply} instead.
*
* @return Returns true if the new values were successfully written
* to persistent storage.
*/
boolean commit();
/**
* Commit your preferences changes back from this Editor to the
* {@link SharedPreferences} object it is editing. This atomically
* performs the requested modifications, replacing whatever is currently
* in the SharedPreferences.
*
* <p>Note that when two editors are modifying preferences at the same
* time, the last one to call apply wins.
*
* <p>Unlike {@link #commit}, which writes its preferences out
* to persistent storage synchronously, {@link #apply}
* commits its changes to the in-memory
* {@link SharedPreferences} immediately but starts an
* asynchronous commit to disk and you won't be notified of
* any failures. If another editor on this
* {@link SharedPreferences} does a regular {@link #commit}
* while a {@link #apply} is still outstanding, the
* {@link #commit} will block until all async commits are
* completed as well as the commit itself.
*
* <p>As {@link SharedPreferences} instances are singletons within
* a process, it's safe to replace any instance of {@link #commit} with
* {@link #apply} if you were already ignoring the return value.
*
* <p>You don't need to worry about Android component
* lifecycles and their interaction with <code>apply()</code>
* writing to disk. The framework makes sure in-flight disk
* writes from <code>apply()</code> complete before switching
* states.
*
* <p class='note'>The SharedPreferences.Editor interface
* isn't expected to be implemented directly. However, if you
* previously did implement it and are now getting errors
* about missing <code>apply()</code>, you can simply call
* {@link #commit} from <code>apply()</code>.
*/
void apply();
}
/**
* Retrieve all values from the preferences.
*
* <p>Note that you <em>must not</em> modify the collection returned
* by this method, or alter any of its contents. The consistency of your
* stored data is not guaranteed if you do.
*
* @return Returns a map containing a list of pairs key/value representing
* the preferences.
*
* @throws NullPointerException
*/
Map<String, ?> getAll();
/**
* Retrieve a String value from the preferences.
*
* @param key The name of the preference to retrieve.
* @param defValue Value to return if this preference does not exist.
*
* @return Returns the preference value if it exists, or defValue. Throws
* ClassCastException if there is a preference with this name that is not
* a String.
*
* @throws ClassCastException
*/
@Nullable
String getString(String key, @Nullable String defValue);
/**
* Retrieve a set of String values from the preferences.
*
* <p>Note that you <em>must not</em> modify the set instance returned
* by this call. The consistency of the stored data is not guaranteed
* if you do, nor is your ability to modify the instance at all.
*
* @param key The name of the preference to retrieve.
* @param defValues Values to return if this preference does not exist.
*
* @return Returns the preference values if they exist, or defValues.
* Throws ClassCastException if there is a preference with this name
* that is not a Set.
*
* @throws ClassCastException
*/
@Nullable
Set<String> getStringSet(String key, @Nullable Set<String> defValues);
/**
* Retrieve an int value from the preferences.
*
* @param key The name of the preference to retrieve.
* @param defValue Value to return if this preference does not exist.
*
* @return Returns the preference value if it exists, or defValue. Throws
* ClassCastException if there is a preference with this name that is not
* an int.
*
* @throws ClassCastException
*/
int getInt(String key, int defValue);
/**
* Retrieve a long value from the preferences.
*
* @param key The name of the preference to retrieve.
* @param defValue Value to return if this preference does not exist.
*
* @return Returns the preference value if it exists, or defValue. Throws
* ClassCastException if there is a preference with this name that is not
* a long.
*
* @throws ClassCastException
*/
long getLong(String key, long defValue);
/**
* Retrieve a float value from the preferences.
*
* @param key The name of the preference to retrieve.
* @param defValue Value to return if this preference does not exist.
*
* @return Returns the preference value if it exists, or defValue. Throws
* ClassCastException if there is a preference with this name that is not
* a float.
*
* @throws ClassCastException
*/
float getFloat(String key, float defValue);
/**
* Retrieve a boolean value from the preferences.
*
* @param key The name of the preference to retrieve.
* @param defValue Value to return if this preference does not exist.
*
* @return Returns the preference value if it exists, or defValue. Throws
* ClassCastException if there is a preference with this name that is not
* a boolean.
*
* @throws ClassCastException
*/
boolean getBoolean(String key, boolean defValue);
/**
* Checks whether the preferences contains a preference.
*
* @param key The name of the preference to check.
* @return Returns true if the preference exists in the preferences,
* otherwise false.
*/
boolean contains(String key);
/**
* Create a new Editor for these preferences, through which you can make
* modifications to the data in the preferences and atomically commit those
* changes back to the SharedPreferences object.
*
* <p>Note that you <em>must</em> call {@link Editor#commit} to have any
* changes you perform in the Editor actually show up in the
* SharedPreferences.
*
* @return Returns a new instance of the {@link Editor} interface, allowing
* you to modify the values in this SharedPreferences object.
*/
Editor edit();
/**
* Registers a callback to be invoked when a change happens to a preference.
*
* <p class="caution"><strong>Caution:</strong> The preference manager does
* not currently store a strong reference to the listener. You must store a
* strong reference to the listener, or it will be susceptible to garbage
* collection. We recommend you keep a reference to the listener in the
* instance data of an object that will exist as long as you need the
* listener.</p>
*
* @param listener The callback that will run.
* @see #unregisterOnSharedPreferenceChangeListener
*/
void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
/**
* Unregisters a previous callback.
*
* @param listener The callback that should be unregistered.
* @see #registerOnSharedPreferenceChangeListener
*/
void unregisterOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener);
}

View File

@ -0,0 +1,999 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content.pm;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import java.text.Collator;
import java.util.Comparator;
/**
* Information you can retrieve about a particular application. This
* corresponds to information collected from the AndroidManifest.xml's
* &lt;application&gt; tag.
*/
public class ApplicationInfo extends PackageItemInfo implements Parcelable {
/**
* Default task affinity of all activities in this application. See
* {@link ActivityInfo#taskAffinity} for more information. This comes
* from the "taskAffinity" attribute.
*/
public String taskAffinity;
/**
* Optional name of a permission required to be able to access this
* application's components. From the "permission" attribute.
*/
public String permission;
/**
* The name of the process this application should run in. From the
* "process" attribute or, if not set, the same as
* <var>packageName</var>.
*/
public String processName;
/**
* Class implementing the Application object. From the "class"
* attribute.
*/
public String className;
/**
* A style resource identifier (in the package's resources) of the
* description of an application. From the "description" attribute
* or, if not set, 0.
*/
public int descriptionRes;
/**
* A style resource identifier (in the package's resources) of the
* default visual theme of the application. From the "theme" attribute
* or, if not set, 0.
*/
public int theme;
/**
* Class implementing the Application's manage space
* functionality. From the "manageSpaceActivity"
* attribute. This is an optional attribute and will be null if
* applications don't specify it in their manifest
*/
public String manageSpaceActivityName;
/**
* Class implementing the Application's backup functionality. From
* the "backupAgent" attribute. This is an optional attribute and
* will be null if the application does not specify it in its manifest.
*
* <p>If android:allowBackup is set to false, this attribute is ignored.
*/
public String backupAgentName;
/**
* An optional attribute that indicates the app supports automatic backup of app data.
* <p>0 is the default and means the app's entire data folder + managed external storage will
* be backed up;
* Any negative value indicates the app does not support full-data backup, though it may still
* want to participate via the traditional key/value backup API;
* A positive number specifies an xml resource in which the application has defined its backup
* include/exclude criteria.
* <p>If android:allowBackup is set to false, this attribute is ignored.
*
* @see android.content.Context#getNoBackupFilesDir()
* @see #FLAG_ALLOW_BACKUP
*
* @hide
*/
public int fullBackupContent = 0;
/**
* The default extra UI options for activities in this application.
* Set from the {@link android.R.attr#uiOptions} attribute in the
* activity's manifest.
*/
public int uiOptions = 0;
/**
* Value for {@link #flags}: if set, this application is installed in the
* device's system image.
*/
public static final int FLAG_SYSTEM = 1<<0;
/**
* Value for {@link #flags}: set to true if this application would like to
* allow debugging of its
* code, even when installed on a non-development system. Comes
* from {@link android.R.styleable#AndroidManifestApplication_debuggable
* android:debuggable} of the &lt;application&gt; tag.
*/
public static final int FLAG_DEBUGGABLE = 1<<1;
/**
* Value for {@link #flags}: set to true if this application has code
* associated with it. Comes
* from {@link android.R.styleable#AndroidManifestApplication_hasCode
* android:hasCode} of the &lt;application&gt; tag.
*/
public static final int FLAG_HAS_CODE = 1<<2;
/**
* Value for {@link #flags}: set to true if this application is persistent.
* Comes from {@link android.R.styleable#AndroidManifestApplication_persistent
* android:persistent} of the &lt;application&gt; tag.
*/
public static final int FLAG_PERSISTENT = 1<<3;
/**
* Value for {@link #flags}: set to true if this application holds the
* {@link android.Manifest.permission#FACTORY_TEST} permission and the
* device is running in factory test mode.
*/
public static final int FLAG_FACTORY_TEST = 1<<4;
/**
* Value for {@link #flags}: default value for the corresponding ActivityInfo flag.
* Comes from {@link android.R.styleable#AndroidManifestApplication_allowTaskReparenting
* android:allowTaskReparenting} of the &lt;application&gt; tag.
*/
public static final int FLAG_ALLOW_TASK_REPARENTING = 1<<5;
/**
* Value for {@link #flags}: default value for the corresponding ActivityInfo flag.
* Comes from {@link android.R.styleable#AndroidManifestApplication_allowClearUserData
* android:allowClearUserData} of the &lt;application&gt; tag.
*/
public static final int FLAG_ALLOW_CLEAR_USER_DATA = 1<<6;
/**
* Value for {@link #flags}: this is set if this application has been
* installed as an update to a built-in system application.
*/
public static final int FLAG_UPDATED_SYSTEM_APP = 1<<7;
/**
* Value for {@link #flags}: this is set if the application has specified
* {@link android.R.styleable#AndroidManifestApplication_testOnly
* android:testOnly} to be true.
*/
public static final int FLAG_TEST_ONLY = 1<<8;
/**
* Value for {@link #flags}: true when the application's window can be
* reduced in size for smaller screens. Corresponds to
* {@link android.R.styleable#AndroidManifestSupportsScreens_smallScreens
* android:smallScreens}.
*/
public static final int FLAG_SUPPORTS_SMALL_SCREENS = 1<<9;
/**
* Value for {@link #flags}: true when the application's window can be
* displayed on normal screens. Corresponds to
* {@link android.R.styleable#AndroidManifestSupportsScreens_normalScreens
* android:normalScreens}.
*/
public static final int FLAG_SUPPORTS_NORMAL_SCREENS = 1<<10;
/**
* Value for {@link #flags}: true when the application's window can be
* increased in size for larger screens. Corresponds to
* {@link android.R.styleable#AndroidManifestSupportsScreens_largeScreens
* android:largeScreens}.
*/
public static final int FLAG_SUPPORTS_LARGE_SCREENS = 1<<11;
/**
* Value for {@link #flags}: true when the application knows how to adjust
* its UI for different screen sizes. Corresponds to
* {@link android.R.styleable#AndroidManifestSupportsScreens_resizeable
* android:resizeable}.
*/
public static final int FLAG_RESIZEABLE_FOR_SCREENS = 1<<12;
/**
* Value for {@link #flags}: true when the application knows how to
* accomodate different screen densities. Corresponds to
* {@link android.R.styleable#AndroidManifestSupportsScreens_anyDensity
* android:anyDensity}.
*/
public static final int FLAG_SUPPORTS_SCREEN_DENSITIES = 1<<13;
/**
* Value for {@link #flags}: set to true if this application would like to
* request the VM to operate under the safe mode. Comes from
* {@link android.R.styleable#AndroidManifestApplication_vmSafeMode
* android:vmSafeMode} of the &lt;application&gt; tag.
*/
public static final int FLAG_VM_SAFE_MODE = 1<<14;
/**
* Value for {@link #flags}: set to <code>false</code> if the application does not wish
* to permit any OS-driven backups of its data; <code>true</code> otherwise.
*
* <p>Comes from the
* {@link android.R.styleable#AndroidManifestApplication_allowBackup android:allowBackup}
* attribute of the &lt;application&gt; tag.
*/
public static final int FLAG_ALLOW_BACKUP = 1<<15;
/**
* Value for {@link #flags}: set to <code>false</code> if the application must be kept
* in memory following a full-system restore operation; <code>true</code> otherwise.
* Ordinarily, during a full system restore operation each application is shut down
* following execution of its agent's onRestore() method. Setting this attribute to
* <code>false</code> prevents this. Most applications will not need to set this attribute.
*
* <p>If
* {@link android.R.styleable#AndroidManifestApplication_allowBackup android:allowBackup}
* is set to <code>false</code> or no
* {@link android.R.styleable#AndroidManifestApplication_backupAgent android:backupAgent}
* is specified, this flag will be ignored.
*
* <p>Comes from the
* {@link android.R.styleable#AndroidManifestApplication_killAfterRestore android:killAfterRestore}
* attribute of the &lt;application&gt; tag.
*/
public static final int FLAG_KILL_AFTER_RESTORE = 1<<16;
/**
* Value for {@link #flags}: Set to <code>true</code> if the application's backup
* agent claims to be able to handle restore data even "from the future,"
* i.e. from versions of the application with a versionCode greater than
* the one currently installed on the device. <i>Use with caution!</i> By default
* this attribute is <code>false</code> and the Backup Manager will ensure that data
* from "future" versions of the application are never supplied during a restore operation.
*
* <p>If
* {@link android.R.styleable#AndroidManifestApplication_allowBackup android:allowBackup}
* is set to <code>false</code> or no
* {@link android.R.styleable#AndroidManifestApplication_backupAgent android:backupAgent}
* is specified, this flag will be ignored.
*
* <p>Comes from the
* {@link android.R.styleable#AndroidManifestApplication_restoreAnyVersion android:restoreAnyVersion}
* attribute of the &lt;application&gt; tag.
*/
public static final int FLAG_RESTORE_ANY_VERSION = 1<<17;
/**
* Value for {@link #flags}: Set to true if the application is
* currently installed on external/removable/unprotected storage. Such
* applications may not be available if their storage is not currently
* mounted. When the storage it is on is not available, it will look like
* the application has been uninstalled (its .apk is no longer available)
* but its persistent data is not removed.
*/
public static final int FLAG_EXTERNAL_STORAGE = 1<<18;
/**
* Value for {@link #flags}: true when the application's window can be
* increased in size for extra large screens. Corresponds to
* {@link android.R.styleable#AndroidManifestSupportsScreens_xlargeScreens
* android:xlargeScreens}.
*/
public static final int FLAG_SUPPORTS_XLARGE_SCREENS = 1<<19;
/**
* Value for {@link #flags}: true when the application has requested a
* large heap for its processes. Corresponds to
* {@link android.R.styleable#AndroidManifestApplication_largeHeap
* android:largeHeap}.
*/
public static final int FLAG_LARGE_HEAP = 1<<20;
/**
* Value for {@link #flags}: true if this application's package is in
* the stopped state.
*/
public static final int FLAG_STOPPED = 1<<21;
/**
* Value for {@link #flags}: true when the application is willing to support
* RTL (right to left). All activities will inherit this value.
*
* Set from the {@link android.R.attr#supportsRtl} attribute in the
* activity's manifest.
*
* Default value is false (no support for RTL).
*/
public static final int FLAG_SUPPORTS_RTL = 1<<22;
/**
* Value for {@link #flags}: true if the application is currently
* installed for the calling user.
*/
public static final int FLAG_INSTALLED = 1<<23;
/**
* Value for {@link #flags}: true if the application only has its
* data installed; the application package itself does not currently
* exist on the device.
*/
public static final int FLAG_IS_DATA_ONLY = 1<<24;
/**
* Value for {@link #flags}: true if the application was declared to be a game, or
* false if it is a non-game application.
*/
public static final int FLAG_IS_GAME = 1<<25;
/**
* Value for {@link #flags}: {@code true} if the application asks that only
* full-data streaming backups of its data be performed even though it defines
* a {@link android.app.backup.BackupAgent BackupAgent}, which normally
* indicates that the app will manage its backed-up data via incremental
* key/value updates.
*/
public static final int FLAG_FULL_BACKUP_ONLY = 1<<26;
/**
* Value for {@link #flags}: {@code true} if the application may use cleartext network traffic
* (e.g., HTTP rather than HTTPS; WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP
* without STARTTLS or TLS). If {@code false}, the app declares that it does not intend to use
* cleartext network traffic, in which case platform components (e.g., HTTP stacks,
* {@code DownloadManager}, {@code MediaPlayer}) will refuse app's requests to use cleartext
* traffic. Third-party libraries are encouraged to honor this flag as well.
*
* <p>NOTE: {@code WebView} does not honor this flag.
*
* <p>This flag is ignored on Android N and above if an Android Network Security Config is
* present.
*
* <p>This flag comes from
* {@link android.R.styleable#AndroidManifestApplication_usesCleartextTraffic
* android:usesCleartextTraffic} of the &lt;application&gt; tag.
*/
public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 1<<27;
/**
* When set installer extracts native libs from .apk files.
*/
public static final int FLAG_EXTRACT_NATIVE_LIBS = 1<<28;
/**
* Value for {@link #flags}: {@code true} when the application's rendering
* should be hardware accelerated.
*/
public static final int FLAG_HARDWARE_ACCELERATED = 1<<29;
/**
* Value for {@link #flags}: true if this application's package is in
* the suspended state.
*/
public static final int FLAG_SUSPENDED = 1<<30;
/**
* Value for {@link #flags}: true if code from this application will need to be
* loaded into other applications' processes. On devices that support multiple
* instruction sets, this implies the code might be loaded into a process that's
* using any of the devices supported instruction sets.
*
* <p> The system might treat such applications specially, for eg., by
* extracting the application's native libraries for all supported instruction
* sets or by compiling the application's dex code for all supported instruction
* sets.
*/
public static final int FLAG_MULTIARCH = 1 << 31;
/**
* Flags associated with the application. Any combination of
* {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE},
* {@link #FLAG_PERSISTENT}, {@link #FLAG_FACTORY_TEST}, and
* {@link #FLAG_ALLOW_TASK_REPARENTING}
* {@link #FLAG_ALLOW_CLEAR_USER_DATA}, {@link #FLAG_UPDATED_SYSTEM_APP},
* {@link #FLAG_TEST_ONLY}, {@link #FLAG_SUPPORTS_SMALL_SCREENS},
* {@link #FLAG_SUPPORTS_NORMAL_SCREENS},
* {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_SUPPORTS_XLARGE_SCREENS},
* {@link #FLAG_RESIZEABLE_FOR_SCREENS},
* {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE},
* {@link #FLAG_ALLOW_BACKUP}, {@link #FLAG_KILL_AFTER_RESTORE},
* {@link #FLAG_RESTORE_ANY_VERSION}, {@link #FLAG_EXTERNAL_STORAGE},
* {@link #FLAG_LARGE_HEAP}, {@link #FLAG_STOPPED},
* {@link #FLAG_SUPPORTS_RTL}, {@link #FLAG_INSTALLED},
* {@link #FLAG_IS_DATA_ONLY}, {@link #FLAG_IS_GAME},
* {@link #FLAG_FULL_BACKUP_ONLY}, {@link #FLAG_USES_CLEARTEXT_TRAFFIC},
* {@link #FLAG_MULTIARCH}.
*/
public int flags = 0;
/**
* Value for {@link #privateFlags}: true if the application is hidden via restrictions and for
* most purposes is considered as not installed.
* {@hide}
*/
public static final int PRIVATE_FLAG_HIDDEN = 1<<0;
/**
* Value for {@link #privateFlags}: set to <code>true</code> if the application
* has reported that it is heavy-weight, and thus can not participate in
* the normal application lifecycle.
*
* <p>Comes from the
* android.R.styleable#AndroidManifestApplication_cantSaveState
* attribute of the &lt;application&gt; tag.
*
* {@hide}
*/
public static final int PRIVATE_FLAG_CANT_SAVE_STATE = 1<<1;
/**
* Value for {@link #privateFlags}: Set to true if the application has been
* installed using the forward lock option.
*
* NOTE: DO NOT CHANGE THIS VALUE! It is saved in packages.xml.
*
* {@hide}
*/
public static final int PRIVATE_FLAG_FORWARD_LOCK = 1<<2;
/**
* Value for {@link #privateFlags}: set to {@code true} if the application
* is permitted to hold privileged permissions.
*
* {@hide}
*/
public static final int PRIVATE_FLAG_PRIVILEGED = 1<<3;
/**
* Value for {@link #privateFlags}: {@code true} if the application has any IntentFiler
* with some data URI using HTTP or HTTPS with an associated VIEW action.
*
* {@hide}
*/
public static final int PRIVATE_FLAG_HAS_DOMAIN_URLS = 1<<4;
/**
* When set, the default data storage directory for this app is pointed at
* the device-protected location.
*
* @hide
*/
public static final int PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE = 1 << 5;
/**
* When set, assume that all components under the given app are direct boot
* aware, unless otherwise specified.
*
* @hide
*/
public static final int PRIVATE_FLAG_DIRECT_BOOT_AWARE = 1 << 6;
/**
* Value for {@link #privateFlags}: set to {@code true} if the application
* is AutoPlay.
*
* {@hide}
*/
public static final int PRIVATE_FLAG_AUTOPLAY = 1 << 7;
/**
* When set, at least one component inside this application is direct boot
* aware.
*
* @hide
*/
public static final int PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE = 1 << 8;
/**
* Value for {@link #flags}: {@code true} if the application is blocked via restrictions
* and for most purposes is considered as not installed.
* {@hide}
*/
public static final int PRIVATE_FLAG_EPHEMERAL = 1 << 9;
/**
* When set, signals that the application is required for the system user and should not be
* uninstalled.
*
* @hide
*/
public static final int PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER = 1 << 10;
/**
* When set, the activities associated with this application are resizeable by default.
* @see android.R.styleable#AndroidManifestActivity_resizeableActivity
*
* @hide
*/
public static final int PRIVATE_FLAG_RESIZEABLE_ACTIVITIES = 1 << 11;
/**
* Value for {@link #privateFlags}: {@code true} means the OS should go ahead and
* run full-data backup operations for the app even when it is in a
* foreground-equivalent run state. Defaults to {@code false} if unspecified.
* @hide
*/
public static final int PRIVATE_FLAG_BACKUP_IN_FOREGROUND = 1 << 12;
/**
* Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.
* {@hide}
*/
public int privateFlags;
/**
* The required smallest screen width the application can run on. If 0,
* nothing has been specified. Comes from
* {@link android.R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp
* android:requiresSmallestWidthDp} attribute of the &lt;supports-screens&gt; tag.
*/
public int requiresSmallestWidthDp = 0;
/**
* The maximum smallest screen width the application is designed for. If 0,
* nothing has been specified. Comes from
* {@link android.R.styleable#AndroidManifestSupportsScreens_compatibleWidthLimitDp
* android:compatibleWidthLimitDp} attribute of the &lt;supports-screens&gt; tag.
*/
public int compatibleWidthLimitDp = 0;
/**
* The maximum smallest screen width the application will work on. If 0,
* nothing has been specified. Comes from
* {@link android.R.styleable#AndroidManifestSupportsScreens_largestWidthLimitDp
* android:largestWidthLimitDp} attribute of the &lt;supports-screens&gt; tag.
*/
public int largestWidthLimitDp = 0;
/** {@hide} */
public String volumeUuid;
/** {@hide} */
public String scanSourceDir;
/** {@hide} */
public String scanPublicSourceDir;
/**
* Full path to the base APK for this application.
*/
public String sourceDir;
/**
* Full path to the publicly available parts of {@link #sourceDir},
* including resources and manifest. This may be different from
* {@link #sourceDir} if an application is forward locked.
*/
public String publicSourceDir;
/**
* Full paths to zero or more split APKs that, when combined with the base
* APK defined in {@link #sourceDir}, form a complete application.
*/
public String[] splitSourceDirs;
/**
* Full path to the publicly available parts of {@link #splitSourceDirs},
* including resources and manifest. This may be different from
* {@link #splitSourceDirs} if an application is forward locked.
*/
public String[] splitPublicSourceDirs;
/**
* Full paths to the locations of extra resource packages this application
* uses. This field is only used if there are extra resource packages,
* otherwise it is null.
*
* {@hide}
*/
public String[] resourceDirs;
/**
* String retrieved from the seinfo tag found in selinux policy. This value
* can be overridden with a value set through the mac_permissions.xml policy
* construct. This value is useful in setting an SELinux security context on
* the process as well as its data directory. The String default is being used
* here to represent a catchall label when no policy matches.
*
* {@hide}
*/
public String seinfo = "default";
/**
* Paths to all shared libraries this application is linked against. This
* field is only set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
* PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving
* the structure.
*/
public String[] sharedLibraryFiles;
/**
* Full path to the default directory assigned to the package for its
* persistent data.
*/
public String dataDir;
/**
* Full path to the device-protected directory assigned to the package for
* its persistent data.
*
* @see Context#createDeviceProtectedStorageContext()
*/
public String deviceProtectedDataDir;
/** @removed */
@Deprecated
public String deviceEncryptedDataDir;
/**
* Full path to the credential-protected directory assigned to the package
* for its persistent data.
*
* @hide
*/
@SystemApi
public String credentialProtectedDataDir;
/** @removed */
@Deprecated
public String credentialEncryptedDataDir;
/**
* Full path to the directory where native JNI libraries are stored.
*/
public String nativeLibraryDir;
/**
* Full path where unpacked native libraries for {@link #secondaryCpuAbi}
* are stored, if present.
*
* The main reason this exists is for bundled multi-arch apps, where
* it's not trivial to calculate the location of libs for the secondary abi
* given the location of the primary.
*
* TODO: Change the layout of bundled installs so that we can use
* nativeLibraryRootDir & nativeLibraryRootRequiresIsa there as well.
* (e.g {@code [ "/system/app-lib/Foo/arm", "/system/app-lib/Foo/arm64" ]}
* instead of {@code [ "/system/lib/Foo", "/system/lib64/Foo" ]}.
*
* @hide
*/
public String secondaryNativeLibraryDir;
/**
* The root path where unpacked native libraries are stored.
* <p>
* When {@link #nativeLibraryRootRequiresIsa} is set, the libraries are
* placed in ISA-specific subdirectories under this path, otherwise the
* libraries are placed directly at this path.
*
* @hide
*/
public String nativeLibraryRootDir;
/**
* Flag indicating that ISA must be appended to
* {@link #nativeLibraryRootDir} to be useful.
*
* @hide
*/
public boolean nativeLibraryRootRequiresIsa;
/**
* The primary ABI that this application requires, This is inferred from the ABIs
* of the native JNI libraries the application bundles. Will be {@code null}
* if this application does not require any particular ABI.
*
* If non-null, the application will always be launched with this ABI.
*
* {@hide}
*/
public String primaryCpuAbi;
/**
* The secondary ABI for this application. Might be non-null for multi-arch
* installs. The application itself never uses this ABI, but other applications that
* use its code might.
*
* {@hide}
*/
public String secondaryCpuAbi;
/**
* The kernel user-ID that has been assigned to this application;
* currently this is not a unique ID (multiple applications can have
* the same uid).
*/
public int uid;
/**
* The minimum SDK version this application can run on. It will not run
* on earlier versions.
*/
public int minSdkVersion;
/**
* The minimum SDK version this application targets. It may run on earlier
* versions, but it knows how to work with any new behavior added at this
* version. Will be {@link android.os.Build.VERSION_CODES#CUR_DEVELOPMENT}
* if this is a development build and the app is targeting that. You should
* compare that this number is >= the SDK version number at which your
* behavior was introduced.
*/
public int targetSdkVersion;
/**
* The app's declared version code.
* @hide
*/
public int versionCode;
/**
* When false, indicates that all components within this application are
* considered disabled, regardless of their individually set enabled status.
*/
public boolean enabled = true;
/**
* For convenient access to the current enabled setting of this app.
* @hide
*/
public int enabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
/**
* For convenient access to package's install location.
* @hide
*/
public int installLocation = PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
/**
* Resource file providing the application's Network Security Config.
* @hide
*/
public int networkSecurityConfigRes;
/**
* @return true if "supportsRtl" has been set to true in the AndroidManifest
* @hide
*/
public boolean hasRtlSupport() {
return (flags & FLAG_SUPPORTS_RTL) == FLAG_SUPPORTS_RTL;
}
/** {@hide} */
public boolean hasCode() {
return (flags & FLAG_HAS_CODE) != 0;
}
public static class DisplayNameComparator
implements Comparator<ApplicationInfo> {
public DisplayNameComparator(PackageManager pm) {
mPM = pm;
}
public final int compare(ApplicationInfo aa, ApplicationInfo ab) {
CharSequence sa = mPM.getApplicationLabel(aa);
if (sa == null) {
sa = aa.packageName;
}
CharSequence sb = mPM.getApplicationLabel(ab);
if (sb == null) {
sb = ab.packageName;
}
return sCollator.compare(sa.toString(), sb.toString());
}
private final Collator sCollator = Collator.getInstance();
private PackageManager mPM;
}
public ApplicationInfo() {
}
public ApplicationInfo(ApplicationInfo orig) {
super(orig);
taskAffinity = orig.taskAffinity;
permission = orig.permission;
processName = orig.processName;
className = orig.className;
theme = orig.theme;
flags = orig.flags;
privateFlags = orig.privateFlags;
requiresSmallestWidthDp = orig.requiresSmallestWidthDp;
compatibleWidthLimitDp = orig.compatibleWidthLimitDp;
largestWidthLimitDp = orig.largestWidthLimitDp;
volumeUuid = orig.volumeUuid;
scanSourceDir = orig.scanSourceDir;
scanPublicSourceDir = orig.scanPublicSourceDir;
sourceDir = orig.sourceDir;
publicSourceDir = orig.publicSourceDir;
splitSourceDirs = orig.splitSourceDirs;
splitPublicSourceDirs = orig.splitPublicSourceDirs;
nativeLibraryDir = orig.nativeLibraryDir;
secondaryNativeLibraryDir = orig.secondaryNativeLibraryDir;
nativeLibraryRootDir = orig.nativeLibraryRootDir;
nativeLibraryRootRequiresIsa = orig.nativeLibraryRootRequiresIsa;
primaryCpuAbi = orig.primaryCpuAbi;
secondaryCpuAbi = orig.secondaryCpuAbi;
resourceDirs = orig.resourceDirs;
seinfo = orig.seinfo;
sharedLibraryFiles = orig.sharedLibraryFiles;
dataDir = orig.dataDir;
deviceEncryptedDataDir = deviceProtectedDataDir = orig.deviceProtectedDataDir;
credentialEncryptedDataDir = credentialProtectedDataDir = orig.credentialProtectedDataDir;
uid = orig.uid;
minSdkVersion = orig.minSdkVersion;
targetSdkVersion = orig.targetSdkVersion;
versionCode = orig.versionCode;
enabled = orig.enabled;
enabledSetting = orig.enabledSetting;
installLocation = orig.installLocation;
manageSpaceActivityName = orig.manageSpaceActivityName;
descriptionRes = orig.descriptionRes;
uiOptions = orig.uiOptions;
backupAgentName = orig.backupAgentName;
fullBackupContent = orig.fullBackupContent;
networkSecurityConfigRes = orig.networkSecurityConfigRes;
}
public String toString() {
return "ApplicationInfo{"
+ Integer.toHexString(System.identityHashCode(this))
+ " " + packageName + "}";
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int parcelableFlags) {
super.writeToParcel(dest, parcelableFlags);
dest.writeString(taskAffinity);
dest.writeString(permission);
dest.writeString(processName);
dest.writeString(className);
dest.writeInt(theme);
dest.writeInt(flags);
dest.writeInt(privateFlags);
dest.writeInt(requiresSmallestWidthDp);
dest.writeInt(compatibleWidthLimitDp);
dest.writeInt(largestWidthLimitDp);
dest.writeString(volumeUuid);
dest.writeString(scanSourceDir);
dest.writeString(scanPublicSourceDir);
dest.writeString(sourceDir);
dest.writeString(publicSourceDir);
dest.writeStringArray(splitSourceDirs);
dest.writeStringArray(splitPublicSourceDirs);
dest.writeString(nativeLibraryDir);
dest.writeString(secondaryNativeLibraryDir);
dest.writeString(nativeLibraryRootDir);
dest.writeInt(nativeLibraryRootRequiresIsa ? 1 : 0);
dest.writeString(primaryCpuAbi);
dest.writeString(secondaryCpuAbi);
dest.writeStringArray(resourceDirs);
dest.writeString(seinfo);
dest.writeStringArray(sharedLibraryFiles);
dest.writeString(dataDir);
dest.writeString(deviceProtectedDataDir);
dest.writeString(credentialProtectedDataDir);
dest.writeInt(uid);
dest.writeInt(minSdkVersion);
dest.writeInt(targetSdkVersion);
dest.writeInt(versionCode);
dest.writeInt(enabled ? 1 : 0);
dest.writeInt(enabledSetting);
dest.writeInt(installLocation);
dest.writeString(manageSpaceActivityName);
dest.writeString(backupAgentName);
dest.writeInt(descriptionRes);
dest.writeInt(uiOptions);
dest.writeInt(fullBackupContent);
dest.writeInt(networkSecurityConfigRes);
}
public static final Parcelable.Creator<ApplicationInfo> CREATOR
= new Parcelable.Creator<ApplicationInfo>() {
public ApplicationInfo createFromParcel(Parcel source) {
return new ApplicationInfo(source);
}
public ApplicationInfo[] newArray(int size) {
return new ApplicationInfo[size];
}
};
private ApplicationInfo(Parcel source) {
super(source);
taskAffinity = source.readString();
permission = source.readString();
processName = source.readString();
className = source.readString();
theme = source.readInt();
flags = source.readInt();
privateFlags = source.readInt();
requiresSmallestWidthDp = source.readInt();
compatibleWidthLimitDp = source.readInt();
largestWidthLimitDp = source.readInt();
volumeUuid = source.readString();
scanSourceDir = source.readString();
scanPublicSourceDir = source.readString();
sourceDir = source.readString();
publicSourceDir = source.readString();
nativeLibraryDir = source.readString();
secondaryNativeLibraryDir = source.readString();
nativeLibraryRootDir = source.readString();
nativeLibraryRootRequiresIsa = source.readInt() != 0;
primaryCpuAbi = source.readString();
secondaryCpuAbi = source.readString();
seinfo = source.readString();
dataDir = source.readString();
deviceEncryptedDataDir = deviceProtectedDataDir = source.readString();
credentialEncryptedDataDir = credentialProtectedDataDir = source.readString();
uid = source.readInt();
minSdkVersion = source.readInt();
targetSdkVersion = source.readInt();
versionCode = source.readInt();
enabled = source.readInt() != 0;
enabledSetting = source.readInt();
installLocation = source.readInt();
manageSpaceActivityName = source.readString();
backupAgentName = source.readString();
descriptionRes = source.readInt();
uiOptions = source.readInt();
fullBackupContent = source.readInt();
networkSecurityConfigRes = source.readInt();
}
/**
* Retrieve the textual description of the application. This
* will call back on the given PackageManager to load the description from
* the application.
*
* @param pm A PackageManager from which the label can be loaded; usually
* the PackageManager from which you originally retrieved this item.
*
* @return Returns a CharSequence containing the application's description.
* If there is no description, null is returned.
*/
public CharSequence loadDescription(PackageManager pm) {
if (descriptionRes != 0) {
CharSequence label = pm.getText(packageName, descriptionRes, this);
if (label != null) {
return label;
}
}
return null;
}
/**
* Disable compatibility mode
*
* @hide
*/
public void disableCompatibilityMode() {
flags |= (FLAG_SUPPORTS_LARGE_SCREENS | FLAG_SUPPORTS_NORMAL_SCREENS |
FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS |
FLAG_SUPPORTS_SCREEN_DENSITIES | FLAG_SUPPORTS_XLARGE_SCREENS);
}
private boolean isPackageUnavailable(PackageManager pm) {
try {
return pm.getPackageInfo(packageName, 0) == null;
} catch (NameNotFoundException ex) {
return true;
}
}
/**
* @hide
*/
public boolean isForwardLocked() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0;
}
/**
* @hide
*/
@TestApi
public boolean isSystemApp() {
return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
/**
* @hide
*/
@TestApi
public boolean isPrivilegedApp() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
}
/**
* @hide
*/
public boolean isUpdatedSystemApp() {
return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}
/** @hide */
public boolean isInternal() {
return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0;
}
/** @hide */
public boolean isExternalAsec() {
return TextUtils.isEmpty(volumeUuid)
&& (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
}
/** @hide */
public boolean isDefaultToDeviceProtectedStorage() {
return (privateFlags
& ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) != 0;
}
/** @hide */
public boolean isDirectBootAware() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE) != 0;
}
/** @hide */
public boolean isPartiallyDirectBootAware() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE) != 0;
}
/**
* @hide
*/
public boolean isAutoPlayApp() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_AUTOPLAY) != 0;
}
/**
* @hide
*/
public boolean isEphemeralApp() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_EPHEMERAL) != 0;
}
/**
* @hide
*/
public boolean isRequiredForSystemUser() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER) != 0;
}
/**
* @hide
*/
protected ApplicationInfo getApplicationInfo() {
return this;
}
/** {@hide} */ public void setCodePath(String codePath) { scanSourceDir = codePath; }
/** {@hide} */ public void setBaseCodePath(String baseCodePath) { sourceDir = baseCodePath; }
/** {@hide} */ public void setSplitCodePaths(String[] splitCodePaths) { splitSourceDirs = splitCodePaths; }
/** {@hide} */ public void setResourcePath(String resourcePath) { scanPublicSourceDir = resourcePath; }
/** {@hide} */ public void setBaseResourcePath(String baseResourcePath) { publicSourceDir = baseResourcePath; }
/** {@hide} */ public void setSplitResourcePaths(String[] splitResourcePaths) { splitPublicSourceDirs = splitResourcePaths; }
/** {@hide} */ public String getCodePath() { return scanSourceDir; }
/** {@hide} */ public String getBaseCodePath() { return sourceDir; }
/** {@hide} */ public String[] getSplitCodePaths() { return splitSourceDirs; }
/** {@hide} */ public String getResourcePath() { return scanPublicSourceDir; }
/** {@hide} */ public String getBaseResourcePath() { return publicSourceDir; }
/** {@hide} */ public String[] getSplitResourcePaths() { return splitSourceDirs; }
}

View File

@ -0,0 +1,132 @@
/*
* Copyright (C) 2009 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.pm;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Definition of a single optional hardware or software feature of an Android
* device.
* <p>
* This object is used to represent both features supported by a device and
* features requested by an app. Apps can request that certain features be
* available as a prerequisite to being installed through the
* {@code uses-feature} tag in their manifests.
* <p>
* Starting in {@link android.os.Build.VERSION_CODES#N}, features can have a
* version, which must always be backwards compatible. That is, a device
* claiming to support version 3 of a specific feature must support apps
* requesting version 1 of that feature.
*/
public class FeatureInfo implements Parcelable {
/**
* The name of this feature, for example "android.hardware.camera". If
* this is null, then this is an OpenGL ES version feature as described
* in {@link #reqGlEsVersion}.
*/
public String name;
/**
* If this object represents a feature supported by a device, this is the
* maximum version of this feature supported by the device. The device
* implicitly supports all older versions of this feature.
* <p>
* If this object represents a feature requested by an app, this is the
* minimum version of the feature required by the app.
* <p>
* When a feature version is undefined by a device, it's assumed to be
* version 0.
*/
public int version;
/**
* Default value for {@link #reqGlEsVersion};
*/
public static final int GL_ES_VERSION_UNDEFINED = 0;
/**
* The GLES version used by an application. The upper order 16 bits represent the
* major version and the lower order 16 bits the minor version. Only valid
* if {@link #name} is null.
*/
public int reqGlEsVersion;
/**
* Set on {@link #flags} if this feature has been required by the application.
*/
public static final int FLAG_REQUIRED = 0x0001;
/**
* Additional flags. May be zero or more of {@link #FLAG_REQUIRED}.
*/
public int flags;
public FeatureInfo() {
}
public FeatureInfo(FeatureInfo orig) {
name = orig.name;
version = orig.version;
reqGlEsVersion = orig.reqGlEsVersion;
flags = orig.flags;
}
@Override
public String toString() {
if (name != null) {
return "FeatureInfo{"
+ Integer.toHexString(System.identityHashCode(this))
+ " " + name + " v=" + version + " fl=0x" + Integer.toHexString(flags) + "}";
} else {
return "FeatureInfo{"
+ Integer.toHexString(System.identityHashCode(this))
+ " glEsVers=" + getGlEsVersion()
+ " fl=0x" + Integer.toHexString(flags) + "}";
}
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int parcelableFlags) {
dest.writeString(name);
dest.writeInt(version);
dest.writeInt(reqGlEsVersion);
dest.writeInt(flags);
}
public static final Creator<FeatureInfo> CREATOR = new Creator<FeatureInfo>() {
@Override
public FeatureInfo createFromParcel(Parcel source) {
return new FeatureInfo(source);
}
@Override
public FeatureInfo[] newArray(int size) {
return new FeatureInfo[size];
}
};
private FeatureInfo(Parcel source) {
name = source.readString();
version = source.readInt();
reqGlEsVersion = source.readInt();
flags = source.readInt();
}
/**
* This method extracts the major and minor version of reqGLEsVersion attribute
* and returns it as a string. Say reqGlEsVersion value of 0x00010002 is returned
* as 1.2
* @return String representation of the reqGlEsVersion attribute
*/
public String getGlEsVersion() {
int major = ((reqGlEsVersion & 0xffff0000) >> 16);
int minor = reqGlEsVersion & 0x0000ffff;
return String.valueOf(major)+"."+String.valueOf(minor);
}
}

View File

@ -0,0 +1,127 @@
/*
* Copyright (C) 2015 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.pm;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import kotlin.NotImplementedError;
/**
* This class represents the state of an instant app. Instant apps can
* be installed or uninstalled. If the app is installed you can call
* {@link #getApplicationInfo()} to get the app info, otherwise this
* class provides APIs to get basic app info for showing it in the UI,
* such as permissions, label, package name.
*
* @hide
*/
@SystemApi
public final class InstantAppInfo implements Parcelable {
private final ApplicationInfo mApplicationInfo;
private final String mPackageName;
private final CharSequence mLabelText;
private final String[] mRequestedPermissions;
private final String[] mGrantedPermissions;
public InstantAppInfo(ApplicationInfo appInfo,
String[] requestedPermissions, String[] grantedPermissions) {
mApplicationInfo = appInfo;
mPackageName = null;
mLabelText = null;
mRequestedPermissions = requestedPermissions;
mGrantedPermissions = grantedPermissions;
}
public InstantAppInfo(String packageName, CharSequence label,
String[] requestedPermissions, String[] grantedPermissions) {
mApplicationInfo = null;
mPackageName = packageName;
mLabelText = label;
mRequestedPermissions = requestedPermissions;
mGrantedPermissions = grantedPermissions;
}
private InstantAppInfo(Parcel parcel) {
throw new NotImplementedError();
}
/**
* @return The application info if the app is installed,
* <code>null</code> otherwise,
*/
public @Nullable ApplicationInfo getApplicationInfo() {
return mApplicationInfo;
}
/**
* @return The package name.
*/
public @NonNull String getPackageName() {
if (mApplicationInfo != null) {
return mApplicationInfo.packageName;
}
return mPackageName;
}
/**
* @param packageManager Package manager for loading resources.
* @return Loads the label if the app is installed or returns the cached one otherwise.
*/
public @NonNull CharSequence loadLabel(@NonNull PackageManager packageManager) {
if (mApplicationInfo != null) {
return mApplicationInfo.loadLabel(packageManager);
}
return mLabelText;
}
/**
* @param packageManager Package manager for loading resources.
* @return Loads the icon if the app is installed or returns the cached one otherwise.
*/
public @NonNull Drawable loadIcon(@NonNull PackageManager packageManager) {
if (mApplicationInfo != null) {
return mApplicationInfo.loadIcon(packageManager);
}
return packageManager.getInstantAppIcon(mPackageName);
}
/**
* @return The requested permissions.
*/
public @Nullable String[] getRequestedPermissions() {
return mRequestedPermissions;
}
/**
* @return The granted permissions.
*/
public @Nullable String[] getGrantedPermissions() {
return mGrantedPermissions;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
throw new NotImplementedError();
}
public static final Creator<InstantAppInfo> CREATOR =
new Creator<InstantAppInfo>() {
@Override
public InstantAppInfo createFromParcel(Parcel parcel) {
return new InstantAppInfo(parcel);
}
@Override
public InstantAppInfo[] newArray(int size) {
return new InstantAppInfo[0];
}
};
}

View File

@ -0,0 +1,223 @@
/*
* Copyright (C) 2015 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.pm;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Set;
/**
* The {@link com.android.server.pm.PackageManagerService} maintains some
* {@link IntentFilterVerificationInfo}s for each domain / package name.
*
* @hide
*/
@SystemApi
public final class IntentFilterVerificationInfo implements Parcelable {
private static final String TAG = IntentFilterVerificationInfo.class.getName();
private static final String TAG_DOMAIN = "domain";
private static final String ATTR_DOMAIN_NAME = "name";
private static final String ATTR_PACKAGE_NAME = "packageName";
private static final String ATTR_STATUS = "status";
private ArraySet<String> mDomains = new ArraySet<>();
private String mPackageName;
private int mMainStatus;
/** @hide */
public IntentFilterVerificationInfo() {
mPackageName = null;
mMainStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
}
/** @hide */
public IntentFilterVerificationInfo(String packageName, ArraySet<String> domains) {
mPackageName = packageName;
mDomains = domains;
mMainStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
}
/** @hide */
public IntentFilterVerificationInfo(XmlPullParser parser)
throws IOException, XmlPullParserException {
readFromXml(parser);
}
/** @hide */
public IntentFilterVerificationInfo(Parcel source) {
readFromParcel(source);
}
public String getPackageName() {
return mPackageName;
}
public int getStatus() {
return mMainStatus;
}
/** @hide */
public void setStatus(int s) {
if (s >= INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED &&
s <= INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) {
mMainStatus = s;
} else {
Log.w(TAG, "Trying to set a non supported status: " + s);
}
}
public Set<String> getDomains() {
return mDomains;
}
/** @hide */
public void setDomains(ArraySet<String> list) {
mDomains = list;
}
/** @hide */
public String getDomainsString() {
StringBuilder sb = new StringBuilder();
for (String str : mDomains) {
if (sb.length() > 0) {
sb.append(" ");
}
sb.append(str);
}
return sb.toString();
}
String getStringFromXml(XmlPullParser parser, String attribute, String defaultValue) {
String value = parser.getAttributeValue(null, attribute);
if (value == null) {
String msg = "Missing element under " + TAG +": " + attribute + " at " +
parser.getPositionDescription();
Log.w(TAG, msg);
return defaultValue;
} else {
return value;
}
}
int getIntFromXml(XmlPullParser parser, String attribute, int defaultValue) {
String value = parser.getAttributeValue(null, attribute);
if (TextUtils.isEmpty(value)) {
String msg = "Missing element under " + TAG +": " + attribute + " at " +
parser.getPositionDescription();
Log.w(TAG, msg);
return defaultValue;
} else {
return Integer.parseInt(value);
}
}
/** @hide */
public void readFromXml(XmlPullParser parser) throws XmlPullParserException,
IOException {
mPackageName = getStringFromXml(parser, ATTR_PACKAGE_NAME, null);
if (mPackageName == null) {
Log.e(TAG, "Package name cannot be null!");
}
int status = getIntFromXml(parser, ATTR_STATUS, -1);
if (status == -1) {
Log.e(TAG, "Unknown status value: " + status);
}
mMainStatus = status;
int outerDepth = parser.getDepth();
int type;
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG
|| parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG
|| type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals(TAG_DOMAIN)) {
String name = getStringFromXml(parser, ATTR_DOMAIN_NAME, null);
if (!TextUtils.isEmpty(name)) {
mDomains.add(name);
}
} else {
Log.w(TAG, "Unknown tag parsing IntentFilter: " + tagName);
}
XmlUtils.skipCurrentTag(parser);
}
}
/** @hide */
public void writeToXml(XmlSerializer serializer) throws IOException {
serializer.attribute(null, ATTR_PACKAGE_NAME, mPackageName);
serializer.attribute(null, ATTR_STATUS, String.valueOf(mMainStatus));
for (String str : mDomains) {
serializer.startTag(null, TAG_DOMAIN);
serializer.attribute(null, ATTR_DOMAIN_NAME, str);
serializer.endTag(null, TAG_DOMAIN);
}
}
/** @hide */
public String getStatusString() {
return getStatusStringFromValue(((long)mMainStatus) << 32);
}
/** @hide */
public static String getStatusStringFromValue(long val) {
StringBuilder sb = new StringBuilder();
switch ((int)(val >> 32)) {
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS:
sb.append("always : ");
sb.append(Long.toHexString(val & 0x00000000FFFFFFFF));
break;
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK:
sb.append("ask");
break;
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER:
sb.append("never");
break;
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK:
sb.append("always-ask");
break;
case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED:
default:
sb.append("undefined");
break;
}
return sb.toString();
}
@Override
public int describeContents() {
return 0;
}
private void readFromParcel(Parcel source) {
mPackageName = source.readString();
mMainStatus = source.readInt();
ArrayList<String> list = new ArrayList<>();
source.readStringList(list);
mDomains.addAll(list);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mPackageName);
dest.writeInt(mMainStatus);
dest.writeStringList(new ArrayList<>(mDomains));
}
public static final Creator<IntentFilterVerificationInfo> CREATOR =
new Creator<IntentFilterVerificationInfo>() {
public IntentFilterVerificationInfo createFromParcel(Parcel source) {
return new IntentFilterVerificationInfo(source);
}
public IntentFilterVerificationInfo[] newArray(int size) {
return new IntentFilterVerificationInfo[size];
}
};
}

View File

@ -0,0 +1,95 @@
/*
* Copyright (C) 2012 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.pm;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Represents a {@code KeySet} that has been declared in the AndroidManifest.xml
* file for the application. A {@code KeySet} can be used explicitly to
* represent a trust relationship with other applications on the device.
* @hide
*/
public class KeySet implements Parcelable {
private IBinder token;
/** @hide */
public KeySet(IBinder token) {
if (token == null) {
throw new NullPointerException("null value for KeySet IBinder token");
}
this.token = token;
}
/** @hide */
public IBinder getToken() {
return token;
}
/** @hide */
@Override
public boolean equals(Object o) {
if (o instanceof KeySet) {
KeySet ks = (KeySet) o;
return token == ks.token;
}
return false;
}
/** @hide */
@Override
public int hashCode() {
return token.hashCode();
}
/**
* Implement Parcelable
* @hide
*/
public static final Parcelable.Creator<KeySet> CREATOR
= new Parcelable.Creator<KeySet>() {
/**
* Create a KeySet from a Parcel
*
* @param source The parcel containing the KeySet
*/
public KeySet createFromParcel(Parcel source) {
return readFromParcel(source);
}
/**
* Create an array of null KeySets
*/
public KeySet[] newArray(int size) {
return new KeySet[size];
}
};
/**
* @hide
*/
private static KeySet readFromParcel(Parcel in) {
IBinder token = in.readStrongBinder();
return new KeySet(token);
}
/**
* @hide
*/
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeStrongBinder(token);
}
/**
* @hide
*/
@Override
public int describeContents() {
return 0;
}
}

View File

@ -0,0 +1,353 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content.pm;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Overall information about the contents of a package. This corresponds
* to all of the information collected from AndroidManifest.xml.
*/
public class PackageInfo implements Parcelable {
/**
* The name of this package. From the &lt;manifest&gt; tag's "name"
* attribute.
*/
public String packageName;
/**
* The names of any installed split APKs for this package.
*/
public String[] splitNames;
/**
* The version number of this package, as specified by the &lt;manifest&gt;
* tag's {@link android.R.styleable#AndroidManifest_versionCode versionCode}
* attribute.
*/
public int versionCode;
/**
* The version name of this package, as specified by the &lt;manifest&gt;
* tag's {@link android.R.styleable#AndroidManifest_versionName versionName}
* attribute.
*/
public String versionName;
/**
* The revision number of the base APK for this package, as specified by the
* &lt;manifest&gt; tag's
* {@link android.R.styleable#AndroidManifest_revisionCode revisionCode}
* attribute.
*/
public int baseRevisionCode;
/**
* The revision number of any split APKs for this package, as specified by
* the &lt;manifest&gt; tag's
* {@link android.R.styleable#AndroidManifest_revisionCode revisionCode}
* attribute. Indexes are a 1:1 mapping against {@link #splitNames}.
*/
public int[] splitRevisionCodes;
/**
* The shared user ID name of this package, as specified by the &lt;manifest&gt;
* tag's {@link android.R.styleable#AndroidManifest_sharedUserId sharedUserId}
* attribute.
*/
public String sharedUserId;
/**
* The shared user ID label of this package, as specified by the &lt;manifest&gt;
* tag's {@link android.R.styleable#AndroidManifest_sharedUserLabel sharedUserLabel}
* attribute.
*/
public int sharedUserLabel;
/**
* Information collected from the &lt;application&gt; tag, or null if
* there was none.
*/
public ApplicationInfo applicationInfo;
/**
* The time at which the app was first installed. Units are as
* per {@link System#currentTimeMillis()}.
*/
public long firstInstallTime;
/**
* The time at which the app was last updated. Units are as
* per {@link System#currentTimeMillis()}.
*/
public long lastUpdateTime;
/**
* All kernel group-IDs that have been assigned to this package.
* This is only filled in if the flag {@link PackageManager#GET_GIDS} was set.
*/
public int[] gids;
/**
* Array of all {@link android.R.styleable#AndroidManifestActivity
* &lt;activity&gt;} tags included under &lt;application&gt;,
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_ACTIVITIES} was set.
*/
public ActivityInfo[] activities;
/**
* Array of all {@link android.R.styleable#AndroidManifestReceiver
* &lt;receiver&gt;} tags included under &lt;application&gt;,
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_RECEIVERS} was set.
*/
public ActivityInfo[] receivers;
/**
* Array of all {@link android.R.styleable#AndroidManifestService
* &lt;service&gt;} tags included under &lt;application&gt;,
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_SERVICES} was set.
*/
public ServiceInfo[] services;
/**
* Array of all {@link android.R.styleable#AndroidManifestProvider
* &lt;provider&gt;} tags included under &lt;application&gt;,
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_PROVIDERS} was set.
*/
public ProviderInfo[] providers;
/**
* Array of all {@link android.R.styleable#AndroidManifestInstrumentation
* &lt;instrumentation&gt;} tags included under &lt;manifest&gt;,
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_INSTRUMENTATION} was set.
*/
public InstrumentationInfo[] instrumentation;
/**
* Array of all {@link android.R.styleable#AndroidManifestPermission
* &lt;permission&gt;} tags included under &lt;manifest&gt;,
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_PERMISSIONS} was set.
*/
public PermissionInfo[] permissions;
/**
* Array of all {@link android.R.styleable#AndroidManifestUsesPermission
* &lt;uses-permission&gt;} tags included under &lt;manifest&gt;,
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_PERMISSIONS} was set. This list includes
* all permissions requested, even those that were not granted or known
* by the system at install time.
*/
public String[] requestedPermissions;
/**
* Array of flags of all {@link android.R.styleable#AndroidManifestUsesPermission
* &lt;uses-permission&gt;} tags included under &lt;manifest&gt;,
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_PERMISSIONS} was set. Each value matches
* the corresponding entry in {@link #requestedPermissions}, and will have
* the flag {@link #REQUESTED_PERMISSION_GRANTED} set as appropriate.
*/
public int[] requestedPermissionsFlags;
/**
* Flag for {@link #requestedPermissionsFlags}: the requested permission
* is required for the application to run; the user can not optionally
* disable it. Currently all permissions are required.
*
* @removed We do not support required permissions.
*/
public static final int REQUESTED_PERMISSION_REQUIRED = 1<<0;
/**
* Flag for {@link #requestedPermissionsFlags}: the requested permission
* is currently granted to the application.
*/
public static final int REQUESTED_PERMISSION_GRANTED = 1<<1;
/**
* Array of all signatures read from the package file. This is only filled
* in if the flag {@link PackageManager#GET_SIGNATURES} was set.
*/
public Signature[] signatures;
/**
* Application specified preferred configuration
* {@link android.R.styleable#AndroidManifestUsesConfiguration
* &lt;uses-configuration&gt;} tags included under &lt;manifest&gt;,
* or null if there were none. This is only filled in if the flag
* {@link PackageManager#GET_CONFIGURATIONS} was set.
*/
public ConfigurationInfo[] configPreferences;
/**
* Features that this application has requested.
*
* @see FeatureInfo#FLAG_REQUIRED
*/
public FeatureInfo[] reqFeatures;
/**
* Groups of features that this application has requested.
* Each group contains a set of features that are required.
* A device must match the features listed in {@link #reqFeatures} and one
* or more FeatureGroups in order to have satisfied the feature requirement.
*
* @see FeatureInfo#FLAG_REQUIRED
*/
public FeatureGroupInfo[] featureGroups;
/**
* Constant corresponding to <code>auto</code> in
* the {@link android.R.attr#installLocation} attribute.
* @hide
*/
public static final int INSTALL_LOCATION_UNSPECIFIED = -1;
/**
* Constant corresponding to <code>auto</code> in the
* {@link android.R.attr#installLocation} attribute.
*/
public static final int INSTALL_LOCATION_AUTO = 0;
/**
* Constant corresponding to <code>internalOnly</code> in the
* {@link android.R.attr#installLocation} attribute.
*/
public static final int INSTALL_LOCATION_INTERNAL_ONLY = 1;
/**
* Constant corresponding to <code>preferExternal</code> in the
* {@link android.R.attr#installLocation} attribute.
*/
public static final int INSTALL_LOCATION_PREFER_EXTERNAL = 2;
/**
* The install location requested by the package. From the
* {@link android.R.attr#installLocation} attribute, one of
* {@link #INSTALL_LOCATION_AUTO}, {@link #INSTALL_LOCATION_INTERNAL_ONLY},
* {@link #INSTALL_LOCATION_PREFER_EXTERNAL}
*/
public int installLocation = INSTALL_LOCATION_INTERNAL_ONLY;
/** @hide */
public boolean coreApp;
/** @hide */
public boolean requiredForAllUsers;
/** @hide */
public String restrictedAccountType;
/** @hide */
public String requiredAccountType;
/**
* What package, if any, this package will overlay.
*
* Package name of target package, or null.
* @hide
*/
public String overlayTarget;
public PackageInfo() {
}
@Override
public String toString() {
return "PackageInfo{"
+ Integer.toHexString(System.identityHashCode(this))
+ " " + packageName + "}";
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int parcelableFlags) {
dest.writeString(packageName);
dest.writeStringArray(splitNames);
dest.writeInt(versionCode);
dest.writeString(versionName);
dest.writeInt(baseRevisionCode);
dest.writeIntArray(splitRevisionCodes);
dest.writeString(sharedUserId);
dest.writeInt(sharedUserLabel);
if (applicationInfo != null) {
dest.writeInt(1);
applicationInfo.writeToParcel(dest, parcelableFlags);
} else {
dest.writeInt(0);
}
dest.writeLong(firstInstallTime);
dest.writeLong(lastUpdateTime);
dest.writeIntArray(gids);
dest.writeTypedArray(activities, parcelableFlags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
dest.writeTypedArray(receivers, parcelableFlags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
dest.writeTypedArray(services, parcelableFlags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
dest.writeTypedArray(providers, parcelableFlags | Parcelable.PARCELABLE_ELIDE_DUPLICATES);
dest.writeTypedArray(instrumentation, parcelableFlags);
dest.writeTypedArray(permissions, parcelableFlags);
dest.writeStringArray(requestedPermissions);
dest.writeIntArray(requestedPermissionsFlags);
dest.writeTypedArray(signatures, parcelableFlags);
dest.writeTypedArray(configPreferences, parcelableFlags);
dest.writeTypedArray(reqFeatures, parcelableFlags);
dest.writeTypedArray(featureGroups, parcelableFlags);
dest.writeInt(installLocation);
dest.writeInt(coreApp ? 1 : 0);
dest.writeInt(requiredForAllUsers ? 1 : 0);
dest.writeString(restrictedAccountType);
dest.writeString(requiredAccountType);
dest.writeString(overlayTarget);
}
public static final Parcelable.Creator<PackageInfo> CREATOR
= new Parcelable.Creator<PackageInfo>() {
@Override
public PackageInfo createFromParcel(Parcel source) {
return new PackageInfo(source);
}
@Override
public PackageInfo[] newArray(int size) {
return new PackageInfo[size];
}
};
private PackageInfo(Parcel source) {
packageName = source.readString();
splitNames = source.createStringArray();
versionCode = source.readInt();
versionName = source.readString();
baseRevisionCode = source.readInt();
splitRevisionCodes = source.createIntArray();
sharedUserId = source.readString();
sharedUserLabel = source.readInt();
int hasApp = source.readInt();
if (hasApp != 0) {
applicationInfo = ApplicationInfo.CREATOR.createFromParcel(source);
}
firstInstallTime = source.readLong();
lastUpdateTime = source.readLong();
gids = source.createIntArray();
activities = source.createTypedArray(ActivityInfo.CREATOR);
receivers = source.createTypedArray(ActivityInfo.CREATOR);
services = source.createTypedArray(ServiceInfo.CREATOR);
providers = source.createTypedArray(ProviderInfo.CREATOR);
instrumentation = source.createTypedArray(InstrumentationInfo.CREATOR);
permissions = source.createTypedArray(PermissionInfo.CREATOR);
requestedPermissions = source.createStringArray();
requestedPermissionsFlags = source.createIntArray();
signatures = source.createTypedArray(Signature.CREATOR);
configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR);
reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
featureGroups = source.createTypedArray(FeatureGroupInfo.CREATOR);
installLocation = source.readInt();
coreApp = source.readInt() != 0;
requiredForAllUsers = source.readInt() != 0;
restrictedAccountType = source.readString();
requiredAccountType = source.readString();
overlayTarget = source.readString();
// The component lists were flattened with the redundant ApplicationInfo
// instances omitted. Distribute the canonical one here as appropriate.
if (applicationInfo != null) {
propagateApplicationInfo(applicationInfo, activities);
propagateApplicationInfo(applicationInfo, receivers);
propagateApplicationInfo(applicationInfo, services);
propagateApplicationInfo(applicationInfo, providers);
}
}
private void propagateApplicationInfo(ApplicationInfo appInfo, ComponentInfo[] components) {
if (components != null) {
for (ComponentInfo ci : components) {
ci.applicationInfo = appInfo;
}
}
}
}

View File

@ -0,0 +1,346 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.content.pm;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcel;
import android.util.Printer;
import kotlin.NotImplementedError;
import java.text.Collator;
import java.util.Comparator;
/**
* Base class containing information common to all package items held by
* the package manager. This provides a very common basic set of attributes:
* a label, icon, and meta-data. This class is not intended
* to be used by itself; it is simply here to share common definitions
* between all items returned by the package manager. As such, it does not
* itself implement Parcelable, but does provide convenience methods to assist
* in the implementation of Parcelable in subclasses.
*/
public class PackageItemInfo {
private static final float MAX_LABEL_SIZE_PX = 500f;
/**
* Public name of this item. From the "android:name" attribute.
*/
public String name;
/**
* Name of the package that this item is in.
*/
public String packageName;
/**
* A string resource identifier (in the package's resources) of this
* component's label. From the "label" attribute or, if not set, 0.
*/
public int labelRes;
/**
* The string provided in the AndroidManifest file, if any. You
* probably don't want to use this. You probably want
* {@link PackageManager#getApplicationLabel}
*/
public CharSequence nonLocalizedLabel;
/**
* A drawable resource identifier (in the package's resources) of this
* component's icon. From the "icon" attribute or, if not set, 0.
*/
public int icon;
/**
* A drawable resource identifier (in the package's resources) of this
* component's banner. From the "banner" attribute or, if not set, 0.
*/
public int banner;
/**
* A drawable resource identifier (in the package's resources) of this
* component's logo. Logos may be larger/wider than icons and are
* displayed by certain UI elements in place of a name or name/icon
* combination. From the "logo" attribute or, if not set, 0.
*/
public int logo;
/**
* Additional meta-data associated with this component. This field
* will only be filled in if you set the
* {@link PackageManager#GET_META_DATA} flag when requesting the info.
*/
public Bundle metaData;
/**
* If different of UserHandle.USER_NULL, The icon of this item will be the one of that user.
* @hide
*/
public int showUserIcon;
public PackageItemInfo() {
// showUserIcon = UserHandle.USER_NULL;
}
public PackageItemInfo(PackageItemInfo orig) {
name = orig.name;
if (name != null) name = name.trim();
packageName = orig.packageName;
labelRes = orig.labelRes;
nonLocalizedLabel = orig.nonLocalizedLabel;
if (nonLocalizedLabel != null) nonLocalizedLabel = nonLocalizedLabel.toString().trim();
icon = orig.icon;
banner = orig.banner;
logo = orig.logo;
metaData = orig.metaData;
showUserIcon = orig.showUserIcon;
}
/**
* Retrieve the current textual label associated with this item. This
* will call back on the given PackageManager to load the label from
* the application.
*
* @param pm A PackageManager from which the label can be loaded; usually
* the PackageManager from which you originally retrieved this item.
*
* @return Returns a CharSequence containing the item's label. If the
* item does not have a label, its name is returned.
*/
public CharSequence loadLabel(PackageManager pm) {
if (nonLocalizedLabel != null) {
return nonLocalizedLabel;
}
if (labelRes != 0) {
CharSequence label = pm.getText(packageName, labelRes, getApplicationInfo());
if (label != null) {
return label.toString().trim();
}
}
if (name != null) {
return name;
}
return packageName;
}
/**
* Retrieve the current graphical icon associated with this item. This
* will call back on the given PackageManager to load the icon from
* the application.
*
* @param pm A PackageManager from which the icon can be loaded; usually
* the PackageManager from which you originally retrieved this item.
*
* @return Returns a Drawable containing the item's icon. If the
* item does not have an icon, the item's default icon is returned
* such as the default activity icon.
*/
public Drawable loadIcon(PackageManager pm) {
throw new NotImplementedError();
}
/**
* Retrieve the current graphical icon associated with this item without
* the addition of a work badge if applicable.
* This will call back on the given PackageManager to load the icon from
* the application.
*
* @param pm A PackageManager from which the icon can be loaded; usually
* the PackageManager from which you originally retrieved this item.
*
* @return Returns a Drawable containing the item's icon. If the
* item does not have an icon, the item's default icon is returned
* such as the default activity icon.
*/
public Drawable loadUnbadgedIcon(PackageManager pm) {
throw new NotImplementedError();
}
/**
* Retrieve the current graphical banner associated with this item. This
* will call back on the given PackageManager to load the banner from
* the application.
*
* @param pm A PackageManager from which the banner can be loaded; usually
* the PackageManager from which you originally retrieved this item.
*
* @return Returns a Drawable containing the item's banner. If the item
* does not have a banner, this method will return null.
*/
public Drawable loadBanner(PackageManager pm) {
if (banner != 0) {
Drawable dr = pm.getDrawable(packageName, banner, getApplicationInfo());
if (dr != null) {
return dr;
}
}
return loadDefaultBanner(pm);
}
/**
* Retrieve the default graphical icon associated with this item.
*
* @param pm A PackageManager from which the icon can be loaded; usually
* the PackageManager from which you originally retrieved this item.
*
* @return Returns a Drawable containing the item's default icon
* such as the default activity icon.
*
* @hide
*/
public Drawable loadDefaultIcon(PackageManager pm) {
return pm.getDefaultActivityIcon();
}
/**
* Retrieve the default graphical banner associated with this item.
*
* @param pm A PackageManager from which the banner can be loaded; usually
* the PackageManager from which you originally retrieved this item.
*
* @return Returns a Drawable containing the item's default banner
* or null if no default logo is available.
*
* @hide
*/
protected Drawable loadDefaultBanner(PackageManager pm) {
return null;
}
/**
* Retrieve the current graphical logo associated with this item. This
* will call back on the given PackageManager to load the logo from
* the application.
*
* @param pm A PackageManager from which the logo can be loaded; usually
* the PackageManager from which you originally retrieved this item.
*
* @return Returns a Drawable containing the item's logo. If the item
* does not have a logo, this method will return null.
*/
public Drawable loadLogo(PackageManager pm) {
if (logo != 0) {
Drawable d = pm.getDrawable(packageName, logo, getApplicationInfo());
if (d != null) {
return d;
}
}
return loadDefaultLogo(pm);
}
/**
* Retrieve the default graphical logo associated with this item.
*
* @param pm A PackageManager from which the logo can be loaded; usually
* the PackageManager from which you originally retrieved this item.
*
* @return Returns a Drawable containing the item's default logo
* or null if no default logo is available.
*
* @hide
*/
protected Drawable loadDefaultLogo(PackageManager pm) {
return null;
}
/**
* Load an XML resource attached to the meta-data of this item. This will
* retrieved the name meta-data entry, and if defined call back on the
* given PackageManager to load its XML file from the application.
*
* @param pm A PackageManager from which the XML can be loaded; usually
* the PackageManager from which you originally retrieved this item.
* @param name Name of the meta-date you would like to load.
*
* @return Returns an XmlPullParser you can use to parse the XML file
* assigned as the given meta-data. If the meta-data name is not defined
* or the XML resource could not be found, null is returned.
*/
public XmlResourceParser loadXmlMetaData(PackageManager pm, String name) {
if (metaData != null) {
int resid = metaData.getInt(name);
if (resid != 0) {
return pm.getXml(packageName, resid, getApplicationInfo());
}
}
return null;
}
/**
* @hide Flag for dumping: include all details.
*/
public static final int DUMP_FLAG_DETAILS = 1<<0;
/**
* @hide Flag for dumping: include nested ApplicationInfo.
*/
public static final int DUMP_FLAG_APPLICATION = 1<<1;
/**
* @hide Flag for dumping: all flags to dump everything.
*/
public static final int DUMP_FLAG_ALL = DUMP_FLAG_DETAILS | DUMP_FLAG_APPLICATION;
protected void dumpFront(Printer pw, String prefix) {
if (name != null) {
pw.println(prefix + "name=" + name);
}
pw.println(prefix + "packageName=" + packageName);
if (labelRes != 0 || nonLocalizedLabel != null || icon != 0 || banner != 0) {
pw.println(prefix + "labelRes=0x" + Integer.toHexString(labelRes)
+ " nonLocalizedLabel=" + nonLocalizedLabel
+ " icon=0x" + Integer.toHexString(icon)
+ " banner=0x" + Integer.toHexString(banner));
}
}
protected void dumpBack(Printer pw, String prefix) {
// no back here
}
public void writeToParcel(Parcel dest, int parcelableFlags) {
dest.writeString(name);
dest.writeString(packageName);
dest.writeInt(labelRes);
dest.writeInt(icon);
dest.writeInt(logo);
dest.writeBundle(metaData);
dest.writeInt(banner);
dest.writeInt(showUserIcon);
}
protected PackageItemInfo(Parcel source) {
name = source.readString();
packageName = source.readString();
labelRes = source.readInt();
icon = source.readInt();
logo = source.readInt();
metaData = source.readBundle();
banner = source.readInt();
showUserIcon = source.readInt();
}
/**
* Get the ApplicationInfo for the application to which this item belongs,
* if available, otherwise returns null.
*
* @return Returns the ApplicationInfo of this item, or null if not known.
*
* @hide
*/
protected ApplicationInfo getApplicationInfo() {
return null;
}
public static class DisplayNameComparator
implements Comparator<PackageItemInfo> {
public DisplayNameComparator(PackageManager pm) {
mPM = pm;
}
public final int compare(PackageItemInfo aa, PackageItemInfo ab) {
CharSequence sa = aa.loadLabel(mPM);
if (sa == null) sa = aa.name;
CharSequence sb = ab.loadLabel(mPM);
if (sb == null) sb = ab.name;
return sCollator.compare(sa.toString(), sb.toString());
}
private final Collator sCollator = Collator.getInstance();
private PackageManager mPM;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
package android.content.pm;
public class PackageParser {
public static class PackageParserException extends Exception {
public final int error;
public PackageParserException(int error, String detailMessage) {
super(detailMessage);
this.error = error;
}
public PackageParserException(int error, String detailMessage, Throwable throwable) {
super(detailMessage, throwable);
this.error = error;
}
}
}

View File

@ -0,0 +1,178 @@
/*
* 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.content.pm;
import android.os.Parcel;
import android.os.Parcelable;
import java.io.ByteArrayInputStream;
import java.lang.ref.SoftReference;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Arrays;
/**
* Opaque, immutable representation of a signature associated with an
* application package.
*/
public class Signature implements Parcelable {
private final byte[] mSignature;
private int mHashCode;
private boolean mHaveHashCode;
private SoftReference<String> mStringRef;
/**
* Create Signature from an existing raw byte array.
*/
public Signature(byte[] signature) {
mSignature = signature.clone();
}
private static final int parseHexDigit(int nibble) {
if ('0' <= nibble && nibble <= '9') {
return nibble - '0';
} else if ('a' <= nibble && nibble <= 'f') {
return nibble - 'a' + 10;
} else if ('A' <= nibble && nibble <= 'F') {
return nibble - 'A' + 10;
} else {
throw new IllegalArgumentException("Invalid character " + nibble + " in hex string");
}
}
/**
* Create Signature from a text representation previously returned by
* {@link #toChars} or {@link #toCharsString()}. Signatures are expected to
* be a hex-encoded ASCII string.
*
* @param text hex-encoded string representing the signature
* @throws IllegalArgumentException when signature is odd-length
*/
public Signature(String text) {
final byte[] input = text.getBytes();
final int N = input.length;
if (N % 2 != 0) {
throw new IllegalArgumentException("text size " + N + " is not even");
}
final byte[] sig = new byte[N / 2];
int sigIndex = 0;
for (int i = 0; i < N;) {
final int hi = parseHexDigit(input[i++]);
final int lo = parseHexDigit(input[i++]);
sig[sigIndex++] = (byte) ((hi << 4) | lo);
}
mSignature = sig;
}
/**
* Encode the Signature as ASCII text.
*/
public char[] toChars() {
return toChars(null, null);
}
/**
* Encode the Signature as ASCII text in to an existing array.
*
* @param existingArray Existing char array or null.
* @param outLen Output parameter for the number of characters written in
* to the array.
* @return Returns either <var>existingArray</var> if it was large enough
* to hold the ASCII representation, or a newly created char[] array if
* needed.
*/
public char[] toChars(char[] existingArray, int[] outLen) {
byte[] sig = mSignature;
final int N = sig.length;
final int N2 = N*2;
char[] text = existingArray == null || N2 > existingArray.length
? new char[N2] : existingArray;
for (int j=0; j<N; j++) {
byte v = sig[j];
int d = (v>>4)&0xf;
text[j*2] = (char)(d >= 10 ? ('a' + d - 10) : ('0' + d));
d = v&0xf;
text[j*2+1] = (char)(d >= 10 ? ('a' + d - 10) : ('0' + d));
}
if (outLen != null) outLen[0] = N;
return text;
}
/**
* Return the result of {@link #toChars()} as a String.
*/
public String toCharsString() {
String str = mStringRef == null ? null : mStringRef.get();
if (str != null) {
return str;
}
str = new String(toChars());
mStringRef = new SoftReference<String>(str);
return str;
}
/**
* @return the contents of this signature as a byte array.
*/
public byte[] toByteArray() {
byte[] bytes = new byte[mSignature.length];
System.arraycopy(mSignature, 0, bytes, 0, mSignature.length);
return bytes;
}
/**
* Returns the public key for this signature.
*
* @throws CertificateException when Signature isn't a valid X.509
* certificate; shouldn't happen.
* @hide
*/
public PublicKey getPublicKey() throws CertificateException {
final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
final ByteArrayInputStream bais = new ByteArrayInputStream(mSignature);
final Certificate cert = certFactory.generateCertificate(bais);
return cert.getPublicKey();
}
@Override
public boolean equals(Object obj) {
try {
if (obj != null) {
Signature other = (Signature)obj;
return this == other || Arrays.equals(mSignature, other.mSignature);
}
} catch (ClassCastException e) {
}
return false;
}
@Override
public int hashCode() {
if (mHaveHashCode) {
return mHashCode;
}
mHashCode = Arrays.hashCode(mSignature);
mHaveHashCode = true;
return mHashCode;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int parcelableFlags) {
dest.writeByteArray(mSignature);
}
public static final Parcelable.Creator<Signature> CREATOR
= new Parcelable.Creator<Signature>() {
public Signature createFromParcel(Parcel source) {
return new Signature(source);
}
public Signature[] newArray(int size) {
return new Signature[size];
}
};
private Signature(Parcel source) {
mSignature = source.createByteArray();
}
}

View File

@ -0,0 +1,87 @@
/*
* Copyright (C) 2017 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.pm;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Encapsulates a package and its version code.
*/
public final class VersionedPackage implements Parcelable {
private final String mPackageName;
private final int mVersionCode;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntRange(from = PackageManager.VERSION_CODE_HIGHEST)
public @interface VersionCode{}
/**
* Creates a new instance. Use {@link PackageManager#VERSION_CODE_HIGHEST}
* to refer to the highest version code of this package.
* @param packageName The package name.
* @param versionCode The version code.
*/
public VersionedPackage(@NonNull String packageName,
@VersionCode int versionCode) {
mPackageName = packageName;
mVersionCode = versionCode;
}
private VersionedPackage(Parcel parcel) {
mPackageName = parcel.readString();
mVersionCode = parcel.readInt();
}
/**
* Gets the package name.
*
* @return The package name.
*/
public @NonNull String getPackageName() {
return mPackageName;
}
/**
* Gets the version code.
*
* @return The version code.
*/
public @VersionCode int getVersionCode() {
return mVersionCode;
}
@Override
public String toString() {
return "VersionedPackage[" + mPackageName + "/" + mVersionCode + "]";
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mPackageName);
parcel.writeInt(mVersionCode);
}
public static final Creator<VersionedPackage> CREATOR = new Creator<VersionedPackage>() {
@Override
public VersionedPackage createFromParcel(Parcel source) {
return new VersionedPackage(source);
}
@Override
public VersionedPackage[] newArray(int size) {
return new VersionedPackage[size];
}
};
}

View File

@ -0,0 +1,296 @@
/*
* 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.res;
import android.content.pm.ApplicationInfo;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
/**
* CompatibilityInfo class keeps the information about compatibility mode that the application is
* running under.
*
* {@hide}
*/
public class CompatibilityInfo implements Parcelable {
/** default compatibility info object for compatible applications */
public static final CompatibilityInfo DEFAULT_COMPATIBILITY_INFO = null;
/**
* This is the number of pixels we would like to have along the
* short axis of an app that needs to run on a normal size screen.
*/
public static final int DEFAULT_NORMAL_SHORT_DIMENSION = 320;
/**
* This is the maximum aspect ratio we will allow while keeping
* applications in a compatible screen size.
*/
public static final float MAXIMUM_ASPECT_RATIO = (854f/480f);
/**
* A compatibility flags
*/
private final int mCompatibilityFlags;
/**
* A flag mask to tell if the application needs scaling (when mApplicationScale != 1.0f)
* {@see compatibilityFlag}
*/
private static final int SCALING_REQUIRED = 1;
/**
* Application must always run in compatibility mode?
*/
private static final int ALWAYS_NEEDS_COMPAT = 2;
/**
* Application never should run in compatibility mode?
*/
private static final int NEVER_NEEDS_COMPAT = 4;
/**
* Set if the application needs to run in screen size compatibility mode.
*/
private static final int NEEDS_SCREEN_COMPAT = 8;
/**
* The effective screen density we have selected for this application.
*/
public final int applicationDensity;
/**
* Application's scale.
*/
public final float applicationScale;
/**
* Application's inverted scale.
*/
public final float applicationInvertedScale;
public CompatibilityInfo(ApplicationInfo appInfo, int screenLayout, int sw, boolean forceCompat) {
throw new RuntimeException("Stub!");
}
private CompatibilityInfo(int compFlags, int dens, float scale, float invertedScale) {
throw new RuntimeException("Stub!");
}
private CompatibilityInfo() {
throw new RuntimeException("Stub!");
}
/**
* @return true if the scaling is required
*/
public boolean isScalingRequired() {
throw new RuntimeException("Stub!");
}
public boolean supportsScreen() {
throw new RuntimeException("Stub!");
}
public boolean neverSupportsScreen() {
throw new RuntimeException("Stub!");
}
public boolean alwaysSupportsScreen() {
throw new RuntimeException("Stub!");
}
/**
* Returns the translator which translates the coordinates in compatibility mode.
* @param params the window's parameter
*/
public Translator getTranslator() {
throw new RuntimeException("Stub!");
}
/**
* A helper object to translate the screen and window coordinates back and forth.
* @hide
*/
public class Translator {
public final float applicationScale;
public final float applicationInvertedScale;
private Rect mContentInsetsBuffer = null;
private Rect mVisibleInsetsBuffer = null;
private Region mTouchableAreaBuffer = null;
Translator(float applicationScale, float applicationInvertedScale) {
throw new RuntimeException("Stub!");
}
Translator() {
throw new RuntimeException("Stub!");
}
/**
* Translate the screen rect to the application frame.
*/
public void translateRectInScreenToAppWinFrame(Rect rect) {
throw new RuntimeException("Stub!");
}
/**
* Translate the region in window to screen.
*/
public void translateRegionInWindowToScreen(Region transparentRegion) {
throw new RuntimeException("Stub!");
}
/**
* Apply translation to the canvas that is necessary to draw the content.
*/
public void translateCanvas(Canvas canvas) {
throw new RuntimeException("Stub!");
}
/**
* Translate the motion event captured on screen to the application's window.
*/
public void translateEventInScreenToAppWindow(MotionEvent event) {
throw new RuntimeException("Stub!");
}
/**
* Translate the window's layout parameter, from application's view to
* Screen's view.
*/
public void translateWindowLayout(WindowManager.LayoutParams params) {
throw new RuntimeException("Stub!");
}
/**
* Translate a Rect in application's window to screen.
*/
public void translateRectInAppWindowToScreen(Rect rect) {
throw new RuntimeException("Stub!");
}
/**
* Translate a Rect in screen coordinates into the app window's coordinates.
*/
public void translateRectInScreenToAppWindow(Rect rect) {
throw new RuntimeException("Stub!");
}
/**
* Translate a Point in screen coordinates into the app window's coordinates.
*/
public void translatePointInScreenToAppWindow(PointF point) {
throw new RuntimeException("Stub!");
}
/**
* Translate the location of the sub window.
* @param params
*/
public void translateLayoutParamsInAppWindowToScreen(LayoutParams params) {
throw new RuntimeException("Stub!");
}
/**
* Translate the content insets in application window to Screen. This uses
* the internal buffer for content insets to avoid extra object allocation.
*/
public Rect getTranslatedContentInsets(Rect contentInsets) {
throw new RuntimeException("Stub!");
}
/**
* Translate the visible insets in application window to Screen. This uses
* the internal buffer for visible insets to avoid extra object allocation.
*/
public Rect getTranslatedVisibleInsets(Rect visibleInsets) {
throw new RuntimeException("Stub!");
}
/**
* Translate the touchable area in application window to Screen. This uses
* the internal buffer for touchable area to avoid extra object allocation.
*/
public Region getTranslatedTouchableArea(Region touchableArea) {
throw new RuntimeException("Stub!");
}
}
public void applyToDisplayMetrics(DisplayMetrics inoutDm) {
throw new RuntimeException("Stub!");
}
public void applyToConfiguration(int displayDensity, Configuration inoutConfig) {
throw new RuntimeException("Stub!");
}
/**
* Compute the frame Rect for applications runs under compatibility mode.
*
* @param dm the display metrics used to compute the frame size.
* @param outDm If non-null the width and height will be set to their scaled values.
* @return Returns the scaling factor for the window.
*/
public static float computeCompatibleScaling(DisplayMetrics dm, DisplayMetrics outDm) {
throw new RuntimeException("Stub!");
}
@Override
public boolean equals(Object o) {
throw new RuntimeException("Stub!");
}
@Override
public String toString() {
throw new RuntimeException("Stub!");
}
@Override
public int hashCode() {
throw new RuntimeException("Stub!");
}
@Override
public int describeContents() {
throw new RuntimeException("Stub!");
}
@Override
public void writeToParcel(Parcel dest, int flags) {
throw new RuntimeException("Stub!");
}
public static final Parcelable.Creator<CompatibilityInfo> CREATOR = null;
private CompatibilityInfo(Parcel source) {
throw new RuntimeException("Stub!");
}
}

View File

@ -0,0 +1,414 @@
/*
* 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.database;
import android.content.ContentResolver;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import kotlin.NotImplementedError;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
/**
* This is an abstract cursor class that handles a lot of the common code
* that all cursors need to deal with and is provided for convenience reasons.
*/
public abstract class AbstractCursor implements CrossProcessCursor {
private static final String TAG = "Cursor";
/**
* @removed This field should not be used.
*/
protected HashMap<Long, Map<String, Object>> mUpdatedRows;
/**
* @removed This field should not be used.
*/
protected int mRowIdColumnIndex;
/**
* @removed This field should not be used.
*/
protected Long mCurrentRowID;
/**
* @deprecated Use {@link #getPosition()} instead.
*/
@Deprecated
protected int mPos;
/**
* @deprecated Use {@link #isClosed()} instead.
*/
@Deprecated
protected boolean mClosed;
/**
* @deprecated Do not use.
*/
@Deprecated
protected ContentResolver mContentResolver;
private Uri mNotifyUri;
private final Object mSelfObserverLock = new Object();
private ContentObserver mSelfObserver;
private boolean mSelfObserverRegistered;
private final DataSetObservable mDataSetObservable = new DataSetObservable();
private final ContentObservable mContentObservable = new ContentObservable();
private Bundle mExtras = Bundle.EMPTY;
/* -------------------------------------------------------- */
/* These need to be implemented by subclasses */
@Override
abstract public int getCount();
@Override
abstract public String[] getColumnNames();
@Override
abstract public String getString(int column);
@Override
abstract public short getShort(int column);
@Override
abstract public int getInt(int column);
@Override
abstract public long getLong(int column);
@Override
abstract public float getFloat(int column);
@Override
abstract public double getDouble(int column);
@Override
abstract public boolean isNull(int column);
@Override
public int getType(int column) {
// Reflects the assumption that all commonly used field types (meaning everything
// but blobs) are convertible to strings so it should be safe to call
// getString to retrieve them.
return FIELD_TYPE_STRING;
}
// TODO implement getBlob in all cursor types
@Override
public byte[] getBlob(int column) {
throw new UnsupportedOperationException("getBlob is not supported");
}
/* -------------------------------------------------------- */
/* Methods that may optionally be implemented by subclasses */
/**
* If the cursor is backed by a {@link CursorWindow}, returns a pre-filled
* window with the contents of the cursor, otherwise null.
*
* @return The pre-filled window that backs this cursor, or null if none.
*/
@Override
public CursorWindow getWindow() {
return null;
}
@Override
public int getColumnCount() {
return getColumnNames().length;
}
@Override
public void deactivate() {
onDeactivateOrClose();
}
/** @hide */
protected void onDeactivateOrClose() {
if (mSelfObserver != null) {
mContentResolver.unregisterContentObserver(mSelfObserver);
mSelfObserverRegistered = false;
}
mDataSetObservable.notifyInvalidated();
}
@Override
public boolean requery() {
if (mSelfObserver != null && mSelfObserverRegistered == false) {
mContentResolver.registerContentObserver(mNotifyUri, true, mSelfObserver);
mSelfObserverRegistered = true;
}
mDataSetObservable.notifyChanged();
return true;
}
@Override
public boolean isClosed() {
return mClosed;
}
@Override
public void close() {
mClosed = true;
mContentObservable.unregisterAll();
onDeactivateOrClose();
}
/**
* This function is called every time the cursor is successfully scrolled
* to a new position, giving the subclass a chance to update any state it
* may have. If it returns false the move function will also do so and the
* cursor will scroll to the beforeFirst position.
*
* @param oldPosition the position that we're moving from
* @param newPosition the position that we're moving to
* @return true if the move is successful, false otherwise
*/
@Override
public boolean onMove(int oldPosition, int newPosition) {
return true;
}
@Override
public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
// Default implementation, uses getString
String result = getString(columnIndex);
if (result != null) {
char[] data = buffer.data;
if (data == null || data.length < result.length()) {
buffer.data = result.toCharArray();
} else {
result.getChars(0, result.length(), data, 0);
}
buffer.sizeCopied = result.length();
} else {
buffer.sizeCopied = 0;
}
}
/* -------------------------------------------------------- */
/* Implementation */
public AbstractCursor() {
mPos = -1;
}
@Override
public final int getPosition() {
return mPos;
}
@Override
public final boolean moveToPosition(int position) {
// Make sure position isn't past the end of the cursor
final int count = getCount();
if (position >= count) {
mPos = count;
return false;
}
// Make sure position isn't before the beginning of the cursor
if (position < 0) {
mPos = -1;
return false;
}
// Check for no-op moves, and skip the rest of the work for them
if (position == mPos) {
return true;
}
boolean result = onMove(mPos, position);
if (result == false) {
mPos = -1;
} else {
mPos = position;
}
return result;
}
@Override
public void fillWindow(int position, CursorWindow window) {
DatabaseUtils.cursorFillWindow(this, position, window);
}
@Override
public final boolean move(int offset) {
return moveToPosition(mPos + offset);
}
@Override
public final boolean moveToFirst() {
return moveToPosition(0);
}
@Override
public final boolean moveToLast() {
return moveToPosition(getCount() - 1);
}
@Override
public final boolean moveToNext() {
return moveToPosition(mPos + 1);
}
@Override
public final boolean moveToPrevious() {
return moveToPosition(mPos - 1);
}
@Override
public final boolean isFirst() {
return mPos == 0 && getCount() != 0;
}
@Override
public final boolean isLast() {
int cnt = getCount();
return mPos == (cnt - 1) && cnt != 0;
}
@Override
public final boolean isBeforeFirst() {
if (getCount() == 0) {
return true;
}
return mPos == -1;
}
@Override
public final boolean isAfterLast() {
if (getCount() == 0) {
return true;
}
return mPos == getCount();
}
@Override
public int getColumnIndex(String columnName) {
// Hack according to bug 903852
final int periodIndex = columnName.lastIndexOf('.');
if (periodIndex != -1) {
Exception e = new Exception();
Log.e(TAG, "requesting column name with table name -- " + columnName, e);
columnName = columnName.substring(periodIndex + 1);
}
String columnNames[] = getColumnNames();
int length = columnNames.length;
for (int i = 0; i < length; i++) {
if (columnNames[i].equalsIgnoreCase(columnName)) {
return i;
}
}
if (false) {
if (getCount() > 0) {
Log.w("AbstractCursor", "Unknown column " + columnName);
}
}
return -1;
}
@Override
public int getColumnIndexOrThrow(String columnName) {
final int index = getColumnIndex(columnName);
if (index < 0) {
throw new IllegalArgumentException("column '" + columnName + "' does not exist");
}
return index;
}
@Override
public String getColumnName(int columnIndex) {
return getColumnNames()[columnIndex];
}
@Override
public void registerContentObserver(ContentObserver observer) {
mContentObservable.registerObserver(observer);
}
@Override
public void unregisterContentObserver(ContentObserver observer) {
// cursor will unregister all observers when it close
if (!mClosed) {
mContentObservable.unregisterObserver(observer);
}
}
@Override
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
/**
* Subclasses must call this method when they finish committing updates to notify all
* observers.
*
* @param selfChange
*/
protected void onChange(boolean selfChange) {
synchronized (mSelfObserverLock) {
mContentObservable.dispatchChange(selfChange, null);
if (mNotifyUri != null && selfChange) {
mContentResolver.notifyChange(mNotifyUri, mSelfObserver);
}
}
}
/**
* Specifies a content URI to watch for changes.
*
* @param cr The content resolver from the caller's context.
* @param notifyUri The URI to watch for changes. This can be a
* specific row URI, or a base URI for a whole class of content.
*/
@Override
public void setNotificationUri(ContentResolver cr, Uri notifyUri) {
throw new NotImplementedError("Not implemented!");
}
@Override
public Uri getNotificationUri() {
synchronized (mSelfObserverLock) {
return mNotifyUri;
}
}
@Override
public boolean getWantsAllOnMoveCalls() {
return false;
}
@Override
public void setExtras(Bundle extras) {
mExtras = (extras == null) ? Bundle.EMPTY : extras;
}
@Override
public Bundle getExtras() {
return mExtras;
}
@Override
public Bundle respond(Bundle extras) {
return Bundle.EMPTY;
}
/**
* @deprecated Always returns false since Cursors do not support updating rows
*/
@Deprecated
protected boolean isFieldUpdated(int columnIndex) {
return false;
}
/**
* @deprecated Always returns null since Cursors do not support updating rows
*/
@Deprecated
protected Object getUpdatedField(int columnIndex) {
return null;
}
/**
* This function throws CursorIndexOutOfBoundsException if
* the cursor position is out of bounds. Subclass implementations of
* the get functions should call this before attempting
* to retrieve data.
*
* @throws CursorIndexOutOfBoundsException
*/
protected void checkPosition() {
if (-1 == mPos || getCount() == mPos) {
throw new CursorIndexOutOfBoundsException(mPos, getCount());
}
}
@Override
protected void finalize() {
if (mSelfObserver != null && mSelfObserverRegistered == true) {
mContentResolver.unregisterContentObserver(mSelfObserver);
}
try {
if (!mClosed) close();
} catch(Exception e) { }
}
/**
* Cursors use this class to track changes others make to their URI.
*/
protected static class SelfContentObserver extends ContentObserver {
WeakReference<AbstractCursor> mCursor;
public SelfContentObserver(AbstractCursor cursor) {
super(null);
mCursor = new WeakReference<AbstractCursor>(cursor);
}
@Override
public boolean deliverSelfNotifications() {
return false;
}
@Override
public void onChange(boolean selfChange) {
AbstractCursor cursor = mCursor.get();
if (cursor != null) {
cursor.onChange(false);
}
}
}
}

View File

@ -0,0 +1,189 @@
/*
* 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.database;
import xyz.nulldev.androidcompat.db.ScrollableResultSet;
/**
* A base class for Cursors that store their data in {@link CursorWindow}s.
* <p>
* The cursor owns the cursor window it uses. When the cursor is closed,
* its window is also closed. Likewise, when the window used by the cursor is
* changed, its old window is closed. This policy of strict ownership ensures
* that cursor windows are not leaked.
* </p><p>
* Subclasses are responsible for filling the cursor window with data during
* {@link #onMove(int, int)}, allocating a new cursor window if necessary.
* During {@link #requery()}, the existing cursor window should be cleared and
* filled with new data.
* </p><p>
* If the contents of the cursor change or become invalid, the old window must be closed
* (because it is owned by the cursor) and set to null.
* </p>
*/
public abstract class AbstractWindowedCursor extends AbstractCursor {
/**
* The cursor window owned by this cursor.
*/
protected CursorWindow mWindow;
@Override
public byte[] getBlob(int columnIndex) {
checkPosition();
return mWindow.getBlob(mPos, columnIndex);
}
@Override
public String getString(int columnIndex) {
checkPosition();
return mWindow.getString(mPos, columnIndex);
}
@Override
public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
checkPosition();
mWindow.copyStringToBuffer(mPos, columnIndex, buffer);
}
@Override
public short getShort(int columnIndex) {
checkPosition();
return mWindow.getShort(mPos, columnIndex);
}
@Override
public int getInt(int columnIndex) {
checkPosition();
return mWindow.getInt(mPos, columnIndex);
}
@Override
public long getLong(int columnIndex) {
checkPosition();
return mWindow.getLong(mPos, columnIndex);
}
@Override
public float getFloat(int columnIndex) {
checkPosition();
return mWindow.getFloat(mPos, columnIndex);
}
@Override
public double getDouble(int columnIndex) {
checkPosition();
return mWindow.getDouble(mPos, columnIndex);
}
@Override
public boolean isNull(int columnIndex) {
checkPosition();
return mWindow.getType(mPos, columnIndex) == Cursor.FIELD_TYPE_NULL;
}
/**
* @deprecated Use {@link #getType}
*/
@Deprecated
public boolean isBlob(int columnIndex) {
return getType(columnIndex) == Cursor.FIELD_TYPE_BLOB;
}
/**
* @deprecated Use {@link #getType}
*/
@Deprecated
public boolean isString(int columnIndex) {
return getType(columnIndex) == Cursor.FIELD_TYPE_STRING;
}
/**
* @deprecated Use {@link #getType}
*/
@Deprecated
public boolean isLong(int columnIndex) {
return getType(columnIndex) == Cursor.FIELD_TYPE_INTEGER;
}
/**
* @deprecated Use {@link #getType}
*/
@Deprecated
public boolean isFloat(int columnIndex) {
return getType(columnIndex) == Cursor.FIELD_TYPE_FLOAT;
}
@Override
public int getType(int columnIndex) {
checkPosition();
return mWindow.getType(mPos, columnIndex);
}
@Override
protected void checkPosition() {
super.checkPosition();
if (mWindow == null) {
throw new StaleDataException("Attempting to access a closed CursorWindow." +
"Most probable cause: cursor is deactivated prior to calling this method.");
}
}
@Override
public CursorWindow getWindow() {
return mWindow;
}
/**
* Sets a new cursor window for the cursor to use.
* <p>
* The cursor takes ownership of the provided cursor window; the cursor window
* will be closed when the cursor is closed or when the cursor adopts a new
* cursor window.
* </p><p>
* If the cursor previously had a cursor window, then it is closed when the
* new cursor window is assigned.
* </p>
*
* @param window The new cursor window, typically a remote cursor window.
*/
public void setWindow(CursorWindow window) {
if (window != mWindow) {
closeWindow();
mWindow = window;
}
}
/**
* Returns true if the cursor has an associated cursor window.
*
* @return True if the cursor has an associated cursor window.
*/
public boolean hasWindow() {
return mWindow != null;
}
/**
* Closes the cursor window and sets {@link #mWindow} to null.
* @hide
*/
protected void closeWindow() {
if (mWindow != null) {
mWindow.close();
mWindow = null;
}
}
/**
* If there is a window, clear it.
* Otherwise, creates a new window.
*
* @hide
*/
protected void clearOrCreateWindow(ScrollableResultSet rs) {
if (mWindow == null) {
mWindow = new CursorWindow(rs);
} else {
mWindow.clear();
}
}
/** @hide */
@Override
protected void onDeactivateOrClose() {
super.onDeactivateOrClose();
closeWindow();
}
}

View File

@ -0,0 +1,31 @@
/*
* 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.database;
/**
* This is used for {@link Cursor#copyStringToBuffer}
*/
public final class CharArrayBuffer {
public CharArrayBuffer(int size) {
data = new char[size];
}
public CharArrayBuffer(char[] buf) {
data = buf;
}
public char[] data; // In and out parameter
public int sizeCopied; // Out parameter
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.database;
import android.net.Uri;
/**
* A specialization of {@link Observable} for {@link ContentObserver}
* that provides methods for sending notifications to a list of
* {@link ContentObserver} objects.
*/
public class ContentObservable extends Observable<ContentObserver> {
// Even though the generic method defined in Observable would be perfectly
// fine on its own, we can't delete this overridden method because it would
// potentially break binary compatibility with existing applications.
@Override
public void registerObserver(ContentObserver observer) {
super.registerObserver(observer);
}
/**
* Invokes {@link ContentObserver#dispatchChange(boolean)} on each observer.
* <p>
* If <code>selfChange</code> is true, only delivers the notification
* to the observer if it has indicated that it wants to receive self-change
* notifications by implementing {@link ContentObserver#deliverSelfNotifications}
* to return true.
* </p>
*
* @param selfChange True if this is a self-change notification.
*
* @deprecated Use {@link #dispatchChange(boolean, Uri)} instead.
*/
@Deprecated
public void dispatchChange(boolean selfChange) {
dispatchChange(selfChange, null);
}
/**
* Invokes {@link ContentObserver#dispatchChange(boolean, Uri)} on each observer.
* Includes the changed content Uri when available.
* <p>
* If <code>selfChange</code> is true, only delivers the notification
* to the observer if it has indicated that it wants to receive self-change
* notifications by implementing {@link ContentObserver#deliverSelfNotifications}
* to return true.
* </p>
*
* @param selfChange True if this is a self-change notification.
* @param uri The Uri of the changed content, or null if unknown.
*/
public void dispatchChange(boolean selfChange, Uri uri) {
synchronized(mObservers) {
for (ContentObserver observer : mObservers) {
if (!selfChange || observer.deliverSelfNotifications()) {
observer.dispatchChange(selfChange, uri);
}
}
}
}
/**
* Invokes {@link ContentObserver#onChange} on each observer.
*
* @param selfChange True if this is a self-change notification.
*
* @deprecated Use {@link #dispatchChange} instead.
*/
@Deprecated
public void notifyChange(boolean selfChange) {
synchronized(mObservers) {
for (ContentObserver observer : mObservers) {
observer.onChange(selfChange, null);
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More