Commit 5c1207be authored by Jean-Baptiste Queru's avatar Jean-Baptiste Queru
Browse files

donut snapshot

parent a8675f67
......@@ -349,7 +349,7 @@ web_docs_sample_code_flags := \
# most current Android platform version included in the SDK package.
framework_docs_SDK_VERSION := 1.5
# release version for SDK (ie "Release x")
framework_docs_SDK_REL_ID := 2
framework_docs_SDK_REL_ID := 3
framework_docs_SDK_CURRENT_DIR := $(framework_docs_SDK_VERSION)_r$(framework_docs_SDK_REL_ID)
framework_docs_LOCAL_DROIDDOC_OPTIONS += \
......@@ -416,7 +416,8 @@ LOCAL_DROIDDOC_OPTIONS:= \
$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
$(web_docs_sample_code_flags) \
-toroot / \
-hdf android.whichdoc online
-hdf android.whichdoc online \
-hdf template.showLanguageMenu true
LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=assets-sdk
......
This diff is collapsed.
......@@ -203,7 +203,6 @@ bool BootAnimation::android() {
mNativeWindowSurface->setSwapRectangle(updateRect.left,
updateRect.top, updateRect.width(), updateRect.height());
glEnable(GL_SCISSOR_TEST);
glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
updateRect.height());
......@@ -219,6 +218,10 @@ bool BootAnimation::android() {
GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
GLint x = xc - offset;
glDisable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h);
......
......@@ -16,6 +16,8 @@
#define LOG_TAG "BootAnimation"
#include <cutils/properties.h>
#include <utils/IPCThreadState.h>
#include <utils/ProcessState.h>
#include <utils/IServiceManager.h>
......@@ -41,12 +43,20 @@ int main(int argc, char** argv)
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
#endif
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.nobootanimation", value, "0");
int noBootAnimation = atoi(value);
LOGI_IF(noBootAnimation, "boot animation disabled");
if (!noBootAnimation) {
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
// create the boot animation object
sp<BootAnimation> boot = new BootAnimation();
// create the boot animation object
sp<BootAnimation> boot = new BootAnimation();
IPCThreadState::self()->joinThreadPool();
IPCThreadState::self()->joinThreadPool();
}
return 0;
}
......@@ -79,14 +79,26 @@ static int encrypt_n_save(AES_KEY *enc_key, DATA_BLOB *blob,
{
int size, fd, ret = -1;
unsigned char enc_blob[MAX_BLOB_LEN];
char tmpfile[KEYFILE_LEN];
if ((keyfile == NULL) || (strlen(keyfile) >= (KEYFILE_LEN - 4))) {
LOGE("keyfile name is too long or null");
return -1;
}
strcpy(tmpfile, keyfile);
strcat(tmpfile, ".tmp");
// prepare the blob
if (IV_LEN > USER_KEY_LEN) {
LOGE("iv length is too long.");
return -1;
}
memcpy(blob->iv, iv, IV_LEN);
blob->blob_size = get_blob_size(blob);
if (blob->blob_size > MAX_BLOB_LEN) {
LOGE("blob data size is too large.");
return -1;
}
memcpy(enc_blob, blob->blob, blob->blob_size);
AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char *)blob->blob,
blob->blob_size, enc_key, iv, AES_ENCRYPT);
......@@ -133,8 +145,13 @@ static int store_master_key(char *upasswd, unsigned char *master_key)
DATA_BLOB blob;
// prepare the blob
if (strlen(MASTER_KEY_TAG) >= USER_KEY_LEN) return -1;
strlcpy(blob.keyname, MASTER_KEY_TAG, USER_KEY_LEN);
blob.value_size = USER_KEY_LEN;
if (USER_KEY_LEN > MAX_KEY_VALUE_LENGTH) {
LOGE("master_key length is too long.");
return -1;
}
memcpy((void*)blob.value, (const void*)master_key, USER_KEY_LEN);
// generate the encryption key
......@@ -150,6 +167,10 @@ static int get_master_key(char *upasswd, unsigned char *master_key)
get_decrypt_key(upasswd, &key);
ret = load_n_decrypt(MASTER_KEY_TAG, MASTER_KEY, &key, &blob);
if (blob.value_size > USER_KEY_LEN) {
LOGE("the blob's value size is too large");
return -1;
}
if (!ret) memcpy(master_key, blob.value, blob.value_size);
return ret;
}
......@@ -207,6 +228,11 @@ int remove_key(const char *namespace, const char *keyname)
char keyfile[KEYFILE_LEN];
if (state != UNLOCKED) return -state;
if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) ||
(strlen(keyname) >= MAX_KEY_NAME_LENGTH)) {
LOGE("keyname is too long.");
return -1;
}
sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
return unlink(keyfile);
}
......@@ -222,10 +248,18 @@ int put_key(const char *namespace, const char *keyname,
LOGE("Can not store key with current state %d\n", state);
return -state;
}
if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) ||
(strlen(keyname) >= MAX_KEY_NAME_LENGTH)) {
LOGE("keyname is too long.");
return -1;
}
sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
// flatten the args
strcpy(blob.keyname, keyname);
blob.value_size = size;
if (size > MAX_KEY_VALUE_LENGTH) {
LOGE("the data size is too large.");
return -1;
}
memcpy(blob.value, data, size);
return encrypt_n_save(&encryptKey, &blob, keyfile);
}
......@@ -242,10 +276,16 @@ int get_key(const char *namespace, const char *keyname,
LOGE("Can not retrieve key value with current state %d\n", state);
return -state;
}
if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) ||
(strlen(keyname) >= MAX_KEY_NAME_LENGTH)) {
LOGE("keyname is too long.");
return -1;
}
sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
ret = load_n_decrypt(keyname, keyfile, &decryptKey, &blob);
if (!ret) {
if ((blob.value_size > MAX_KEY_VALUE_LENGTH)) {
LOGE("blob value size is too large.");
ret = -1;
} else {
*size = blob.value_size;
......@@ -269,6 +309,13 @@ int list_keys(const char *namespace, char reply[BUFFER_MAX])
LOGE("cannot open keystore dir or namespace is null\n");
return -1;
}
if (strlen(namespace) >= MAX_KEY_NAME_LENGTH) {
LOGE("namespace is too long.");
return -1;
}
reply[0] = 0;
while ((de = readdir(d))) {
char *prefix, *name, *keyfile = de->d_name;
char *context = NULL;
......@@ -337,6 +384,7 @@ KEYSTORE_STATE get_state()
int reset_keystore()
{
int ret = 0;
DIR *d;
struct dirent *de;
......@@ -344,18 +392,24 @@ int reset_keystore()
LOGE("cannot open keystore dir\n");
return -1;
}
while ((de = readdir(d))) unlink(de->d_name);
while ((de = readdir(d))) {
if (unlink(de->d_name) != 0) ret = -1;
}
closedir(d);
state = UNINITIALIZED;
LOGI("keystore is reset.");
return 0;
if (ret == 0) {
LOGI("keystore is reset.");
} else {
LOGI("keystore can not be cleaned up entirely.");
}
return ret;
}
int init_keystore(const char *dir)
{
int fd;
if (!dir) mkdir(dir, 0770);
if (dir) mkdir(dir, 0770);
if (!dir || chdir(dir)) {
LOGE("Can not open/create the keystore directory %s\n",
dir ? dir : "(null)");
......
# 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.
#
# define the KEYSTORE_TESTS environment variable to build the test programs
ifdef KEYSTORE_TESTS
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= netkeystore_test.c ../keymgmt.c
LOCAL_SHARED_LIBRARIES := libcutils libssl
LOCAL_MODULE:= netkeystore_test
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := external/openssl/include \
frameworks/base/cmds/keystore
EXTRA_CFLAGS := -g -O0 -DGTEST_OS_LINUX -DGTEST_HAS_STD_STRING
include $(BUILD_EXECUTABLE)
endif #KEYSTORE_TESTS
/*
* Copyright (C) 2009 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "common.h"
#include "keymgmt.h"
typedef int FUNC_PTR();
typedef struct {
const char *name;
FUNC_PTR *func;
} TESTFUNC;
#define FUNC_NAME(x) { #x, test_##x }
#define FUNC_BODY(x) int test_##x()
#define TEST_PASSWD "12345678"
#define TEST_NPASSWD "11111111"
#define TEST_DIR "/data/local/tmp/keystore"
#define READONLY_DIR "/proc/keystore"
#define TEST_NAMESPACE "test"
#define TEST_KEYNAME "key"
#define TEST_KEYNAME2 "key2"
#define TEST_KEYVALUE "ANDROID"
void setup()
{
if (init_keystore(TEST_DIR) != 0) {
fprintf(stderr, "Can not create the test directory %s\n", TEST_DIR);
exit(-1);
}
}
void teardown()
{
reset_keystore();
rmdir(TEST_DIR);
}
FUNC_BODY(init_keystore)
{
if (init_keystore(READONLY_DIR) == 0) return -1;
return EXIT_SUCCESS;
}
FUNC_BODY(reset_keystore)
{
chdir("/procx");
if (reset_keystore() == 0) return -1;
chdir(TEST_DIR);
return EXIT_SUCCESS;
}
FUNC_BODY(get_state)
{
if (get_state() != UNINITIALIZED) return -1;
passwd(TEST_PASSWD);
if (get_state() != UNLOCKED) return -1;
lock();
if (get_state() != LOCKED) return -1;
reset_keystore();
if (get_state() != UNINITIALIZED) return -1;
return EXIT_SUCCESS;
}
FUNC_BODY(passwd)
{
char buf[512];
if (passwd(" 23432dsfsdf") == 0) return -1;
if (passwd("dsfsdf") == 0) return -1;
passwd(TEST_PASSWD);
lock();
if (unlock("55555555") == 0) return -1;
if (unlock(TEST_PASSWD) != 0) return -1;
// change the password
sprintf(buf, "%s %s", "klfdjdsklfjg", "abcdefghi");
if (passwd(buf) == 0) return -1;
sprintf(buf, "%s %s", TEST_PASSWD, TEST_NPASSWD);
if (passwd(buf) != 0) return -1;
lock();
if (unlock(TEST_PASSWD) == 0) return -1;
if (unlock(TEST_NPASSWD) != 0) return -1;
return EXIT_SUCCESS;
}
FUNC_BODY(lock)
{
if (lock() == 0) return -1;
passwd(TEST_PASSWD);
if (lock() != 0) return -1;
if (lock() != 0) return -1;
return EXIT_SUCCESS;
}
FUNC_BODY(unlock)
{
int i = MAX_RETRY_COUNT;
passwd(TEST_PASSWD);
lock();
while (i > 1) {
if (unlock(TEST_NPASSWD) != --i) return -1;
}
if (unlock(TEST_NPASSWD) != -1) return -1;
return EXIT_SUCCESS;
}
FUNC_BODY(put_key)
{
int i = 0;
char keyname[512];
if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
strlen(TEST_KEYVALUE)) == 0) return -1;
passwd(TEST_PASSWD);
if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
strlen(TEST_KEYVALUE)) != 0) return -1;
for(i = 0; i < 500; i++) keyname[i] = 'K';
keyname[i] = 0;
if (put_key(TEST_NAMESPACE, keyname, (unsigned char *)TEST_KEYVALUE,
strlen(TEST_KEYVALUE)) == 0) return -1;
if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
MAX_KEY_VALUE_LENGTH + 1) == 0) return -1;
return EXIT_SUCCESS;
}
FUNC_BODY(get_key)
{
int size;
unsigned char data[MAX_KEY_VALUE_LENGTH];
if (get_key(TEST_NAMESPACE, TEST_KEYNAME, data, &size) == 0) return -1;
passwd(TEST_PASSWD);
put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
strlen(TEST_KEYVALUE));
if (get_key(TEST_NAMESPACE, TEST_KEYNAME, data, &size) != 0) return -1;
if (memcmp(data, TEST_KEYVALUE, size) != 0) return -1;
return EXIT_SUCCESS;
}
FUNC_BODY(remove_key)
{
if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) == 0) return -1;
passwd(TEST_PASSWD);
if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) == 0) return -1;
put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
strlen(TEST_KEYVALUE));
if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) != 0) return -1;
return EXIT_SUCCESS;
}
FUNC_BODY(list_keys)
{
int i;
char buf[128];
char reply[BUFFER_MAX];
for(i = 0; i < 100; i++) buf[i] = 'K';
buf[i] = 0;
if (list_keys(TEST_NAMESPACE, reply) == 0) return -1;
passwd(TEST_PASSWD);
if (list_keys(buf, reply) == 0) return -1;
if (list_keys(TEST_NAMESPACE, reply) != 0) return -1;
if (strcmp(reply, "") != 0) return -1;
put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
strlen(TEST_KEYVALUE));
if (list_keys(TEST_NAMESPACE, reply) != 0) return -1;
if (strcmp(reply, TEST_KEYNAME) != 0) return -1;
put_key(TEST_NAMESPACE, TEST_KEYNAME2, (unsigned char *)TEST_KEYVALUE,
strlen(TEST_KEYVALUE));
if (list_keys(TEST_NAMESPACE, reply) != 0) return -1;
sprintf(buf, "%s %s", TEST_KEYNAME2, TEST_KEYNAME);
if (strcmp(reply, buf) != 0) return -1;
return EXIT_SUCCESS;
}
TESTFUNC all_tests[] = {
FUNC_NAME(init_keystore),
FUNC_NAME(reset_keystore),
FUNC_NAME(get_state),
FUNC_NAME(passwd),
FUNC_NAME(lock),
FUNC_NAME(unlock),
FUNC_NAME(put_key),
FUNC_NAME(get_key),
FUNC_NAME(remove_key),
FUNC_NAME(list_keys),
};
int main(int argc, char **argv) {
int i, ret;
for (i = 0 ; i < (int)(sizeof(all_tests)/sizeof(TESTFUNC)) ; ++i) {
setup();
if ((ret = all_tests[i].func()) != EXIT_SUCCESS) {
fprintf(stderr, "ERROR in function %s\n", all_tests[i].name);
return ret;
} else {
fprintf(stderr, "function %s PASSED!\n", all_tests[i].name);
}
teardown();
}
return EXIT_SUCCESS;
}
......@@ -163,6 +163,10 @@ public abstract class AccessibilityService extends Service {
}
}
/**
* Implement to return the implementation of the internal accessibility
* service interface. Subclasses should not override.
*/
@Override
public final IBinder onBind(Intent intent) {
return new IEventListenerWrapper(this);
......
......@@ -1085,6 +1085,23 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeInt(result);
return true;
}
case KILL_APPLICATION_WITH_UID_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
String pkg = data.readString();
int uid = data.readInt();
killApplicationWithUid(pkg, uid);
reply.writeNoException();
return true;
}
case CLOSE_SYSTEM_DIALOGS_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
String reason = data.readString();
closeSystemDialogs(reason);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
......@@ -2368,6 +2385,29 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
return result;
}
public void killApplicationWithUid(String pkg, int uid) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeString(pkg);
data.writeInt(uid);
mRemote.transact(KILL_APPLICATION_WITH_UID_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
public void closeSystemDialogs(String reason) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeString(reason);
mRemote.transact(CLOSE_SYSTEM_DIALOGS_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
private IBinder mRemote;
}
......@@ -177,11 +177,17 @@ public final class ActivityThread {
synchronized (mPackages) {
// Resources is app scale dependent.
ResourcesKey key = new ResourcesKey(resDir, compInfo.applicationScale);
//Log.w(TAG, "getTopLevelResources: " + resDir);
if (false) {
Log.w(TAG, "getTopLevelResources: " + resDir + " / "
+ compInfo.applicationScale);
}
WeakReference<Resources> wr = mActiveResources.get(key);
Resources r = wr != null ? wr.get() : null;
if (r != null && r.getAssets().isUpToDate()) {
//Log.w(TAG, "Returning cached resources " + r + " " + resDir);
if (false) {
Log.w(TAG, "Returning cached resources " + r + " " + resDir
+ ": appScale=" + r.getCompatibilityInfo().applicationScale);
}
return r;
}
......@@ -198,7 +204,11 @@ public final class ActivityThread {
//Log.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
DisplayMetrics metrics = getDisplayMetricsLocked(false);
r = new Resources(assets, metrics, getConfiguration(), compInfo);
//Log.i(TAG, "Created app resources " + r + ": " + r.getConfiguration());
if (false) {
Log.i(TAG, "Created app resources " + resDir + " " + r + ": "
+ r.getConfiguration() + " appScale="
+ r.getCompatibilityInfo().applicationScale);
}
// XXX need to remove entries when weak references go away
mActiveResources.put(key, new WeakReference<Resources>(r));
return r;
......@@ -3624,7 +3634,7 @@ public final class ActivityThread {
Locale.setDefault(config.locale);
}
Resources.updateSystemConfiguration(config, null);
Resources.updateSystemConfiguration(config, dm);
ApplicationContext.ApplicationPackageManager.configurationChanged();
//Log.i(TAG, "Configuration changed in " + currentPackageName());
......@@ -3743,6 +3753,14 @@ public final class ActivityThread {
data.info = getPackageInfoNoCheck(data.appInfo);
/**
* Switch this process to density compatibility mode if needed.
*/
if ((data.appInfo.flags&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
== 0) {
Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
}
if (data.debugMode != IApplicationThread.DEBUG_OFF) {
// XXX should have option to change the port.
Debug.changeDebugPort(8100);
......
......@@ -541,7 +541,10 @@ class ApplicationContext extends Context {
if (fd != null) {
Bitmap bm = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor());
if (bm != null) {
return new BitmapDrawable(bm);
// For now clear the density until we figure out how
// to deal with it for wallpapers.
bm.setDensity(0);
return new BitmapDrawable(getResources(), bm);
}
}
} catch (RemoteException e) {
......@@ -1949,6 +1952,15 @@ class ApplicationContext extends Context {
try {
Resources r = getResourcesForApplication(appInfo);
dr = r.getDrawable(resid);
if (false) {
RuntimeException e = new RuntimeException("here");
e.fillInStackTrace();
Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resid)
+ " from package " + packageName
+ ": app scale=" + r.getCompatibilityInfo().applicationScale
+ ", caller scale=" + mContext.getResources().getCompatibilityInfo().applicationScale,
e);
}
if (DEBUG_ICONS) Log.v(TAG, "Getting drawable 0x"
+ Integer.toHexString(resid) + " from " + r
+ ": " + dr);
......@@ -2036,10 +2048,9 @@ class ApplicationContext extends Context {
if (app.packageName.equals("system")) {
return mContext.mMainThread.getSystemContext().getResources();
}
ActivityThread.PackageInfo pi = mContext.mMainThread.getPackageInfoNoCheck(app);
Resources r = mContext.mMainThread.getTopLevelResources(
app.uid == Process.myUid() ? app.sourceDir
: app.publicSourceDir, pi);
: app.publicSourceDir, mContext.mPackageInfo);
if (r != null) {
return r;
}
......
......@@ -266,7 +266,11 @@ public interface IActivityManager extends IInterface {
Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, boolean onlyIfNeeded)
throws RemoteException;
public void killApplicationWithUid(String pkg, int uid) throws RemoteException;
public void closeSystemDialogs(String reason) throws RemoteException;
/*
* Private non-Binder interfaces
*/
......@@ -421,4 +425,6 @@ public interface IActivityManager extends IInterface {
int REGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92;
int UNREGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93;
int START_ACTIVITY_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94;
int KILL_APPLICATION_WITH_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95;
int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96;
}
......@@ -23,4 +23,5 @@ package android.app;
*/
oneway interface IActivityWatcher {
void activityResuming(int activityId);
void closingSystemDialogs(String reason);
}
......@@ -297,7 +297,7 @@ public abstract class LauncherActivity extends ListActivity {
icon.setBounds(x, y, x + width, y + height);
icon.draw(canvas);
icon.setBounds(mOldBounds);
icon = new BitmapDrawable(thumb);
icon = new BitmapDrawable(getResources(), thumb);
} else if (iconWidth < width && iconHeight < height) {
final Bitmap.Config c = Bitmap.Config.ARGB_8888;
final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c);
......@@ -309,7 +309,7 @@ public abstract class LauncherActivity extends ListActivity {
icon.setBounds(x, y, x + iconWidth, y + iconHeight);
icon.draw(canvas);
icon.setBounds(mOldBounds);
icon = new BitmapDrawable(thumb);
icon = new BitmapDrawable(getResources(), thumb);
}
}
......
......@@ -273,11 +273,6 @@ public final class PendingIntent implements Parcelable {
return null;
}
private class IntentSenderWrapper extends IntentSender {
protected IntentSenderWrapper(IIntentSender target) {
super(target);
}
}
/**
* Retrieve a IntentSender object that wraps the existing sender of the PendingIntent
*
......@@ -285,7 +280,7 @@ public final class PendingIntent implements Parcelable {
*
*/
public IntentSender getIntentSender() {
return new IntentSenderWrapper(mTarget);
return new IntentSender(mTarget);
}
/**
......
......@@ -34,7 +34,10 @@ import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Browser;
import android.server.search.SearchableInfo;
import android.speech.RecognizerIntent;
import android.text.Editable;
......@@ -42,11 +45,13 @@ import android.text.InputType;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.util.Regex;
import android.util.AndroidRuntimeException;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
......@@ -240,7 +245,12 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
return success;
}
private boolean isInRealAppSearch() {
return !mGlobalSearchMode
&& (mPreviousComponents == null || mPreviousComponents.isEmpty());
}
/**
* Called in response to a press of the hard search button in
* {@link #onKeyDown(int, KeyEvent)}, this method toggles between in-app
......@@ -260,6 +270,16 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
if (!mGlobalSearchMode) {
mStoredComponentName = mLaunchComponent;
mStoredAppSearchData = mAppSearchData;
// If this is the browser, we have a special case to not show the icon to the left
// of the text field, for extra space for url entry (this should be reconciled in
// Eclair). So special case a second tap of the search button to remove any
// already-entered text so that we can be sure to show the "Quick Search Box" hint
// text to still make it clear to the user that we've jumped out to global search.
//
// TODO: When the browser icon issue is reconciled in Eclair, remove this special case.
if (isBrowserSearch()) currentSearchText = "";
return doShow(currentSearchText, false, null, mAppSearchData, true);
} else {
if (mStoredComponentName != null) {
......@@ -531,12 +551,14 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// we dismiss the entire dialog instead
mSearchAutoComplete.setDropDownDismissedOnCompletion(false);
if (mGlobalSearchMode) {
if (!isInRealAppSearch()) {
mSearchAutoComplete.setDropDownAlwaysVisible(true); // fill space until results come in
} else {
mSearchAutoComplete.setDropDownAlwaysVisible(false);
}
mSearchAutoComplete.setForceIgnoreOutsideTouch(true);
// attach the suggestions adapter, if suggestions are available
// The existence of a suggestions authority is the proxy for "suggestions available here"
if (mSearchable.getSuggestAuthority() != null) {
......@@ -565,7 +587,11 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
}
private void updateSearchAppIcon() {
if (mGlobalSearchMode) {
// In Donut, we special-case the case of the browser to hide the app icon as if it were
// global search, for extra space for url entry.
//
// TODO: Remove this special case once the issue has been reconciled in Eclair.
if (mGlobalSearchMode || isBrowserSearch()) {
mAppIcon.setImageResource(0);
mAppIcon.setVisibility(View.GONE);
mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_GLOBAL,
......@@ -657,6 +683,49 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
mVoiceButton.setVisibility(visibility);
}
/**
* Hack to determine whether this is the browser, so we can remove the browser icon
* to the left of the search field, as a special requirement for Donut.
*
* TODO: For Eclair, reconcile this with the rest of the global search UI.
*/
private boolean isBrowserSearch() {
return mLaunchComponent.flattenToShortString().startsWith("com.android.browser/");
}
/*
* Menu.
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Show search settings menu item if anyone handles the intent for it
Intent settingsIntent = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS);
settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PackageManager pm = getContext().getPackageManager();
ActivityInfo activityInfo = settingsIntent.resolveActivityInfo(pm, 0);
if (activityInfo != null) {
settingsIntent.setClassName(activityInfo.applicationInfo.packageName,
activityInfo.name);
CharSequence label = activityInfo.loadLabel(getContext().getPackageManager());
menu.add(Menu.NONE, Menu.NONE, Menu.NONE, label)
.setIcon(android.R.drawable.ic_menu_preferences)
.setAlphabeticShortcut('P')
.setIntent(settingsIntent);
return true;
}
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
// The menu shows up above the IME, regardless of whether it is in front
// of the drop-down or not. This looks weird when there is no IME, so
// we make sure it is visible.
mSearchAutoComplete.ensureImeVisible();
return super.onMenuOpened(featureId, menu);
}
/**
* Listeners of various types
*/
......@@ -794,7 +863,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
if (!event.isSystem() &&
(keyCode != KeyEvent.KEYCODE_DPAD_UP) &&
(keyCode != KeyEvent.KEYCODE_DPAD_DOWN) &&
(keyCode != KeyEvent.KEYCODE_DPAD_LEFT) &&
(keyCode != KeyEvent.KEYCODE_DPAD_RIGHT) &&
(keyCode != KeyEvent.KEYCODE_DPAD_CENTER)) {
......@@ -835,6 +903,12 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
getContext().startActivity(mVoiceWebSearchIntent);
} else if (mSearchable.getVoiceSearchLaunchRecognizer()) {
Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent);
// Stop the existing search before starting voice search, or else we'll end
// up showing the search dialog again once we return to the app.
((SearchManager) getContext().getSystemService(Context.SEARCH_SERVICE)).
stopSearch();
getContext().startActivity(appSearchIntent);
}
} catch (ActivityNotFoundException e) {
......@@ -1093,7 +1167,8 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
*/
protected void launchQuerySearch(int actionKey, String actionMsg) {
String query = mSearchAutoComplete.getText().toString();
Intent intent = createIntent(Intent.ACTION_SEARCH, null, null, query, null,
String action = mGlobalSearchMode ? Intent.ACTION_WEB_SEARCH : Intent.ACTION_SEARCH;
Intent intent = createIntent(action, null, null, query, null,
actionKey, actionMsg);
launchIntent(intent);
}
......@@ -1169,11 +1244,11 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
// ensure the icons will work for global search
cv.put(SearchManager.SUGGEST_COLUMN_ICON_1,
wrapIconForPackage(
source,
mSearchable.getSuggestPackage(),
getColumnString(c, SearchManager.SUGGEST_COLUMN_ICON_1)));
cv.put(SearchManager.SUGGEST_COLUMN_ICON_2,
wrapIconForPackage(
source,
mSearchable.getSuggestPackage(),
getColumnString(c, SearchManager.SUGGEST_COLUMN_ICON_2)));
// the rest can be passed through directly
......@@ -1212,11 +1287,11 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
* Wraps an icon for a particular package. If the icon is a resource id, it is converted into
* an android.resource:// URI.
*
* @param source The source of the icon
* @param packageName The source of the icon
* @param icon The icon retrieved from a suggestion column
* @return An icon string appropriate for the package.
*/
private String wrapIconForPackage(ComponentName source, String icon) {
private String wrapIconForPackage(String packageName, String icon) {
if (icon == null || icon.length() == 0 || "0".equals(icon)) {
// SearchManager specifies that null or zero can be returned to indicate
// no icon. We also allow empty string.
......@@ -1224,7 +1299,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
} else if (!Character.isDigit(icon.charAt(0))){
return icon;
} else {
String packageName = source.getPackageName();
return new Uri.Builder()
.scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
.authority(packageName)
......@@ -1245,16 +1319,133 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
return;
}
Log.d(LOG_TAG, "launching " + intent);
getContext().startActivity(intent);
try {
// in global search mode, we send the activity straight to the original suggestion
// source. this is because GlobalSearch may not have permission to launch the
// intent, and to avoid the extra step of going through GlobalSearch.
if (mGlobalSearchMode) {
launchGlobalSearchIntent(intent);
} else {
// If the intent was created from a suggestion, it will always have an explicit
// component here.
Log.i(LOG_TAG, "Starting (as ourselves) " + intent.toURI());
getContext().startActivity(intent);
// If the search switches to a different activity,
// SearchDialogWrapper#performActivityResuming
// will handle hiding the dialog when the next activity starts, but for
// real in-app search, we still need to dismiss the dialog.
if (isInRealAppSearch()) {
dismiss();
}
}
} catch (RuntimeException ex) {
Log.e(LOG_TAG, "Failed launch activity: " + intent, ex);
}
}
// in global search mode, SearchDialogWrapper#performActivityResuming will handle hiding
// the dialog when the next activity starts, but for in-app search, we still need to
// dismiss the dialog.
if (!mGlobalSearchMode) {
dismiss();
private void launchGlobalSearchIntent(Intent intent) {
final String packageName;
// GlobalSearch puts the original source of the suggestion in the
// 'component name' column. If set, we send the intent to that activity.
// We trust GlobalSearch to always set this to the suggestion source.
String intentComponent = intent.getStringExtra(SearchManager.COMPONENT_NAME_KEY);
if (intentComponent != null) {
ComponentName componentName = ComponentName.unflattenFromString(intentComponent);
intent.setComponent(componentName);
intent.removeExtra(SearchManager.COMPONENT_NAME_KEY);
// Launch the intent as the suggestion source.
// This prevents sources from using the search dialog to launch
// intents that they don't have permission for themselves.
packageName = componentName.getPackageName();
} else {
// If there is no component in the suggestion, it must be a built-in suggestion
// from GlobalSearch (e.g. "Search the web for") or the intent
// launched when pressing the search/go button in the search dialog.
// Launch the intent with the permissions of GlobalSearch.
packageName = mSearchable.getSearchActivity().getPackageName();
}
// Launch all global search suggestions as new tasks, since they don't relate
// to the current task.
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
setBrowserApplicationId(intent);
startActivityInPackage(intent, packageName);
}
/**
* If the intent is to open an HTTP or HTTPS URL, we set
* {@link Browser#EXTRA_APPLICATION_ID} so that any existing browser window that
* has been opened by us for the same URL will be reused.
*/
private void setBrowserApplicationId(Intent intent) {
Uri data = intent.getData();
if (Intent.ACTION_VIEW.equals(intent.getAction()) && data != null) {
String scheme = data.getScheme();
if (scheme != null && scheme.startsWith("http")) {
intent.putExtra(Browser.EXTRA_APPLICATION_ID, data.toString());
}
}
}
/**
* Starts an activity as if it had been started by the given package.
*
* @param intent The description of the activity to start.
* @param packageName
* @throws ActivityNotFoundException If the intent could not be resolved to
* and existing activity.
* @throws SecurityException If the package does not have permission to start
* start the activity.
* @throws AndroidRuntimeException If some other error occurs.
*/
private void startActivityInPackage(Intent intent, String packageName) {
try {
int uid = ActivityThread.getPackageManager().getPackageUid(packageName);
if (uid < 0) {
throw new AndroidRuntimeException("Package UID not found " + packageName);
}
String resolvedType = intent.resolveTypeIfNeeded(getContext().getContentResolver());
IBinder resultTo = null;
String resultWho = null;
int requestCode = -1;
boolean onlyIfNeeded = false;
Log.i(LOG_TAG, "Starting (uid " + uid + ", " + packageName + ") " + intent.toURI());
int result = ActivityManagerNative.getDefault().startActivityInPackage(
uid, intent, resolvedType, resultTo, resultWho, requestCode, onlyIfNeeded);
checkStartActivityResult(result, intent);
} catch (RemoteException ex) {
throw new AndroidRuntimeException(ex);
}
}
// Stolen from Instrumentation.checkStartActivityResult()
private static void checkStartActivityResult(int res, Intent intent) {
if (res >= IActivityManager.START_SUCCESS) {
return;
}
switch (res) {
case IActivityManager.START_INTENT_NOT_RESOLVED:
case IActivityManager.START_CLASS_NOT_FOUND:
if (intent.getComponent() != null)
throw new ActivityNotFoundException(
"Unable to find explicit activity class "
+ intent.getComponent().toShortString()
+ "; have you declared this activity in your AndroidManifest.xml?");
throw new ActivityNotFoundException(
"No Activity found to handle " + intent);
case IActivityManager.START_PERMISSION_DENIED:
throw new SecurityException("Not allowed to start activity "
+ intent);
case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
throw new AndroidRuntimeException(
"FORWARD_RESULT_FLAG used while also requesting a result");
default:
throw new AndroidRuntimeException("Unknown error code "
+ res + " when starting " + intent);
}
}
/**
* Handles the special intent actions declared in {@link SearchManager}.
*
......@@ -1284,13 +1475,13 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
return;
}
if (DBG) Log.d(LOG_TAG, "Switching to " + componentName);
ComponentName previous = mLaunchComponent;
pushPreviousComponent(mLaunchComponent);
if (!show(componentName, mAppSearchData, false)) {
Log.w(LOG_TAG, "Failed to switch to source " + componentName);
popPreviousComponent();
return;
}
pushPreviousComponent(previous);
String query = intent.getStringExtra(SearchManager.QUERY);
setUserQuery(query);
......@@ -1460,8 +1651,10 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
intent.putExtra(SearchManager.ACTION_KEY, actionKey);
intent.putExtra(SearchManager.ACTION_MSG, actionMsg);
}
// attempt to enforce security requirement (no 3rd-party intents)
intent.setComponent(mSearchable.getSearchActivity());
// Only allow 3rd-party intents from GlobalSearch
if (!mGlobalSearchMode) {
intent.setComponent(mSearchable.getSearchActivity());
}
return intent;
}
......@@ -1582,6 +1775,12 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
if (mSearchDialog.backToPreviousComponent()) {
return true;
}
// If the drop-down obscures the keyboard, the user wouldn't see anything
// happening when pressing back, so we dismiss the entire dialog instead.
if (isInputMethodNotNeeded()) {
mSearchDialog.cancel();
return true;
}
return false; // will dismiss soft keyboard if necessary
}
return false;
......
......@@ -1214,19 +1214,14 @@ public class SearchManager
public final static String POST_REFRESH_RECEIVE_DISPLAY_NOTIFY
= "DialogCursorProtocol.POST_REFRESH.displayNotify";
/**
* Just before closing the cursor.
*/
public final static int PRE_CLOSE = 1;
public final static String PRE_CLOSE_SEND_MAX_DISPLAY_POS
= "DialogCursorProtocol.PRE_CLOSE.sendDisplayPosition";
/**
* When a position has been clicked.
*/
public final static int CLICK = 2;
public final static String CLICK_SEND_POSITION
= "DialogCursorProtocol.CLICK.sendPosition";
public final static String CLICK_SEND_MAX_DISPLAY_POS
= "DialogCursorProtocol.CLICK.sendDisplayPosition";
public final static String CLICK_RECEIVE_SELECTED_POS
= "DialogCursorProtocol.CLICK.receiveSelectedPosition";
......
......@@ -27,6 +27,7 @@ import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.DrawableContainer;
import android.graphics.drawable.StateListDrawable;
import android.net.Uri;
import android.os.Bundle;
......@@ -135,6 +136,8 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
private int mPreviousLength = 0;
public long getPostingDelay(CharSequence constraint) {
if (constraint == null) return 0;
long delay = constraint.length() < mPreviousLength ? DELETE_KEY_POST_DELAY : 0;
mPreviousLength = constraint.length();
return delay;
......@@ -191,37 +194,21 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
public void changeCursor(Cursor c) {
if (DBG) Log.d(LOG_TAG, "changeCursor(" + c + ")");
if (mCursor != null) {
callCursorPreClose(mCursor);
}
super.changeCursor(c);
if (c != null) {
mFormatCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT);
mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1);
mText2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2);
mIconName1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1);
mIconName2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2);
mBackgroundColorCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_BACKGROUND_COLOR);
try {
super.changeCursor(c);
if (c != null) {
mFormatCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT);
mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1);
mText2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2);
mIconName1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1);
mIconName2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2);
mBackgroundColorCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_BACKGROUND_COLOR);
}
} catch (Exception e) {
Log.e(LOG_TAG, "error changing cursor and caching columns", e);
}
}
/**
* Handle sending and receiving information associated with
* {@link DialogCursorProtocol#PRE_CLOSE}.
*
* @param cursor The cursor to call.
*/
private void callCursorPreClose(Cursor cursor) {
if (!mGlobalSearchMode) return;
final Bundle request = new Bundle();
request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.PRE_CLOSE);
request.putInt(DialogCursorProtocol.PRE_CLOSE_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
final Bundle response = cursor.respond(request);
mMaxDisplayed = -1;
}
@Override
public void notifyDataSetChanged() {
if (DBG) Log.d(LOG_TAG, "notifyDataSetChanged");
......@@ -267,7 +254,9 @@ class SuggestionsAdapter extends ResourceCursorAdapter {
final Bundle request = new Bundle(1);
request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.CLICK);
request.putInt(DialogCursorProtocol.CLICK_SEND_POSITION, position);
request.putInt(DialogCursorProtocol.CLICK_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
final Bundle response = cursor.respond(request);
mMaxDisplayed = -1;
mListItemToSelect = response.getInt(
DialogCursorProtocol.CLICK_RECEIVE_SELECTED_POS, SuggestionsAdapter.NONE);
}
......
......@@ -1283,7 +1283,8 @@ public abstract class Context {
* Use with {@link #getSystemService} to retrieve an
* {@blink android.backup.IBackupManager IBackupManager} for communicating
* with the backup mechanism.
*
* @hide
*
* @see #getSystemService
*/
public static final String BACKUP_SERVICE = "backup";
......
......@@ -135,6 +135,7 @@ public class ContextWrapper extends Context {
return mBase.getPackageCodePath();
}
/** @hide */
@Override
public File getSharedPrefsFile(String name) {
return mBase.getSharedPrefsFile(name);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment