diff options
30 files changed, 609 insertions, 244 deletions
diff --git a/api/current.xml b/api/current.xml index b704eb3fdc8d..000f5d9c6ff4 100644 --- a/api/current.xml +++ b/api/current.xml @@ -8391,6 +8391,17 @@ visibility="public" > </field> +<field name="userVisible" + type="int" + transient="false" + volatile="false" + value="16843408" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="value" type="int" transient="false" @@ -8758,7 +8769,7 @@ type="int" transient="false" volatile="false" - value="16843408" + value="16843409" static="true" final="true" deprecated="not deprecated" @@ -27586,6 +27597,17 @@ visibility="public" > </field> +<field name="SYNC_EXTRAS_INITIALIZE" + type="java.lang.String" + transient="false" + volatile="false" + value=""initialize"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="SYNC_EXTRAS_MANUAL" type="java.lang.String" transient="false" @@ -35766,6 +35788,8 @@ </parameter> <parameter name="accountType" type="java.lang.String"> </parameter> +<parameter name="userVisible" type="boolean"> +</parameter> </constructor> <constructor name="SyncAdapterType" type="android.content.SyncAdapterType" @@ -35788,6 +35812,21 @@ visibility="public" > </method> +<method name="newKey" + return="android.content.SyncAdapterType" + abstract="false" + native="false" + synchronized="false" + static="true" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="authority" type="java.lang.String"> +</parameter> +<parameter name="accountType" type="java.lang.String"> +</parameter> +</method> <method name="writeToParcel" return="void" abstract="false" @@ -35833,11 +35872,10 @@ visibility="public" > </field> -<field name="isUserFacing" +<field name="userVisible" type="boolean" transient="false" volatile="false" - value="true" static="false" final="true" deprecated="not deprecated" @@ -113994,6 +114032,17 @@ visibility="public" > </field> +<field name="ACTION_TTS_DATA_INSTALLED" + type="java.lang.String" + transient="false" + volatile="false" + value=""android.speech.tts.engine.TTS_DATA_INSTALLED"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="CHECK_VOICE_DATA_BAD_DATA" type="int" transient="false" @@ -114060,6 +114109,17 @@ visibility="public" > </field> +<field name="EXTRA_TTS_DATA_INSTALLED" + type="java.lang.String" + transient="false" + volatile="false" + value=""dataInstalled"" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="EXTRA_VOICE_DATA_FILES" type="java.lang.String" transient="false" diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index c05e042d0b9f..10e629913a96 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2522,7 +2522,7 @@ public class Activity extends ContextThemeWrapper * no extra data is required. * @param globalSearch If false, this will only launch the search that has been specifically * defined by the application (which is usually defined as a local search). If no default - * search is defined in the current application or activity, no search will be launched. + * search is defined in the current application or activity, global search will be launched. * If true, this will always launch a platform-global (e.g. web-based) search instead. * * @see android.app.SearchManager diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index 15a277ca2b14..a460d1906d29 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -1698,7 +1698,7 @@ public class SearchManager * no extra data is required. * @param globalSearch If false, this will only launch the search that has been specifically * defined by the application (which is usually defined as a local search). If no default - * search is defined in the current application or activity, no search will be launched. + * search is defined in the current application or activity, global search will be launched. * If true, this will always launch a platform-global (e.g. web-based) search instead. * * @see android.app.Activity#onSearchRequested diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java index f15a902cb032..538225a0a5ee 100644 --- a/core/java/android/content/AbstractThreadedSyncAdapter.java +++ b/core/java/android/content/AbstractThreadedSyncAdapter.java @@ -44,16 +44,23 @@ public abstract class AbstractThreadedSyncAdapter { /** Kernel event log tag. Also listed in data/etc/event-log-tags. */ public static final int LOG_SYNC_DETAILS = 2743; + private final boolean mAutoInitialize; /** * Creates an {@link AbstractThreadedSyncAdapter}. - * @param context the {@link Context} that this is running within. + * @param context the {@link android.content.Context} that this is running within. + * @param autoInitialize if true then sync requests that have + * {@link ContentResolver#SYNC_EXTRAS_INITIALIZE} set will be internally handled by + * {@link AbstractThreadedSyncAdapter} by calling + * {@link ContentResolver#setIsSyncable(android.accounts.Account, String, int)} with 1 if it + * is currently set to <0. */ - public AbstractThreadedSyncAdapter(Context context) { + public AbstractThreadedSyncAdapter(Context context, boolean autoInitialize) { mContext = context; mISyncAdapterImpl = new ISyncAdapterImpl(); mNumSyncStarts = new AtomicInteger(0); mSyncThread = null; + mAutoInitialize = autoInitialize; } class ISyncAdapterImpl extends ISyncAdapter.Stub { @@ -66,6 +73,15 @@ public abstract class AbstractThreadedSyncAdapter { // check it and when we use it synchronized (this) { if (mSyncThread == null) { + if (mAutoInitialize + && extras != null + && extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) { + if (ContentResolver.getIsSyncable(account, authority) < 0) { + ContentResolver.setIsSyncable(account, authority, 1); + } + syncContextClient.onFinished(new SyncResult()); + return; + } mSyncThread = new SyncThread( "SyncAdapterThread-" + mNumSyncStarts.incrementAndGet(), syncContextClient, authority, account, extras); diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index bf1a4425f604..239b3defe895 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -52,18 +52,29 @@ public abstract class ContentResolver { * @deprecated instead use * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)} */ + @Deprecated public static final String SYNC_EXTRAS_ACCOUNT = "account"; public static final String SYNC_EXTRAS_EXPEDITED = "expedited"; /** * @deprecated instead use * {@link #SYNC_EXTRAS_MANUAL} */ + @Deprecated public static final String SYNC_EXTRAS_FORCE = "force"; public static final String SYNC_EXTRAS_MANUAL = "force"; public static final String SYNC_EXTRAS_UPLOAD = "upload"; public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override"; public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions"; + /** + * Set by the SyncManager to request that the SyncAdapter initialize itself for + * the given account/authority pair. One required initialization step is to + * ensure that {@link #setIsSyncable(android.accounts.Account, String, int)} has been + * called with a >= 0 value. When this flag is set the SyncAdapter does not need to + * do a full sync, though it is allowed to do so. + */ + public static final String SYNC_EXTRAS_INITIALIZE = "initialize"; + public static final String SCHEME_CONTENT = "content"; public static final String SCHEME_ANDROID_RESOURCE = "android.resource"; public static final String SCHEME_FILE = "file"; @@ -1094,8 +1105,7 @@ public abstract class ContentResolver { } /** - * Returns the status that matches the authority. If there are multiples accounts for - * the authority, the one with the latest "lastSuccessTime" status is returned. + * Returns the status that matches the authority. * @param account the account whose setting we are querying * @param authority the provider whose behavior is being queried * @return the SyncStatusInfo for the authority, or null if none exists diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java index c4d8aafd4178..f7424487dcfe 100644 --- a/core/java/android/content/ContentService.java +++ b/core/java/android/content/ContentService.java @@ -197,7 +197,8 @@ public final class ContentService extends IContentService.Stub { try { SyncManager syncManager = getSyncManager(); if (syncManager != null) { - syncManager.scheduleSync(account, authority, extras, 0 /* no delay */); + syncManager.scheduleSync(account, authority, extras, 0 /* no delay */, + false /* onlyThoseWithUnkownSyncableState */); } } finally { restoreCallingIdentity(identityToken); diff --git a/core/java/android/content/SyncAdapter.java b/core/java/android/content/SyncAdapter.java index 1d5ade17ae90..88dc3320d351 100644 --- a/core/java/android/content/SyncAdapter.java +++ b/core/java/android/content/SyncAdapter.java @@ -32,7 +32,7 @@ public abstract class SyncAdapter { class Transport extends ISyncAdapter.Stub { public void startSync(ISyncContext syncContext, String authority, Account account, Bundle extras) throws RemoteException { - SyncAdapter.this.startSync(new SyncContext(syncContext), account, extras); + SyncAdapter.this.startSync(new SyncContext(syncContext), account, authority, extras); } public void cancelSync(ISyncContext syncContext) throws RemoteException { @@ -58,9 +58,11 @@ public abstract class SyncAdapter { * @param syncContext the ISyncContext used to indicate the progress of the sync. When * the sync is finished (successfully or not) ISyncContext.onFinished() must be called. * @param account the account that should be synced + * @param authority the authority if the sync request * @param extras SyncAdapter-specific parameters */ - public abstract void startSync(SyncContext syncContext, Account account, Bundle extras); + public abstract void startSync(SyncContext syncContext, Account account, String authority, + Bundle extras); /** * Cancel the most recently initiated sync. Due to race conditions, this may arrive diff --git a/core/java/android/content/SyncAdapterType.java b/core/java/android/content/SyncAdapterType.java index d3f8230cb5b0..93b61ecc9a92 100644 --- a/core/java/android/content/SyncAdapterType.java +++ b/core/java/android/content/SyncAdapterType.java @@ -27,9 +27,9 @@ import android.os.Parcel; public class SyncAdapterType implements Parcelable { public final String authority; public final String accountType; - public final boolean isUserFacing = true; // TODO: implement logic to set this + public final boolean userVisible; - public SyncAdapterType(String authority, String accountType) { + public SyncAdapterType(String authority, String accountType, boolean userVisible) { if (TextUtils.isEmpty(authority)) { throw new IllegalArgumentException("the authority must not be empty: " + authority); } @@ -38,12 +38,18 @@ public class SyncAdapterType implements Parcelable { } this.authority = authority; this.accountType = accountType; + this.userVisible = userVisible; + } + + public static SyncAdapterType newKey(String authority, String accountType) { + return new SyncAdapterType(authority, accountType, true); } public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof SyncAdapterType)) return false; final SyncAdapterType other = (SyncAdapterType)o; + // don't include userVisible in the equality check return authority.equals(other.authority) && accountType.equals(other.accountType); } @@ -51,11 +57,13 @@ public class SyncAdapterType implements Parcelable { int result = 17; result = 31 * result + authority.hashCode(); result = 31 * result + accountType.hashCode(); + // don't include userVisible in the hash return result; } public String toString() { - return "SyncAdapterType {name=" + authority + ", type=" + accountType + "}"; + return "SyncAdapterType {name=" + authority + ", type=" + accountType + + ", userVisible=" + userVisible + "}"; } public int describeContents() { @@ -65,10 +73,11 @@ public class SyncAdapterType implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeString(authority); dest.writeString(accountType); + dest.writeInt(userVisible ? 1 : 0); } public SyncAdapterType(Parcel source) { - this(source.readString(), source.readString()); + this(source.readString(), source.readString(), source.readInt() != 0); } public static final Creator<SyncAdapterType> CREATOR = new Creator<SyncAdapterType>() { diff --git a/core/java/android/content/SyncAdaptersCache.java b/core/java/android/content/SyncAdaptersCache.java index ce47d7672fb1..c27fd259ee12 100644 --- a/core/java/android/content/SyncAdaptersCache.java +++ b/core/java/android/content/SyncAdaptersCache.java @@ -47,7 +47,9 @@ import android.util.AttributeSet; if (authority == null || accountType == null) { return null; } - return new SyncAdapterType(authority, accountType); + final boolean userVisible = + sa.getBoolean(com.android.internal.R.styleable.SyncAdapter_userVisible, true); + return new SyncAdapterType(authority, accountType, userVisible); } finally { sa.recycle(); } diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index f50fd74662ae..34efc51f21d5 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -180,7 +180,8 @@ class SyncManager implements OnAccountsUpdatedListener { }; public void onAccountsUpdated(Account[] accounts) { - final boolean hadAccountsAlready = mAccounts != null; + // remember if this was the first time this was called after an update + final boolean justBootedUp = mAccounts == null; mAccounts = accounts; // if a sync is in progress yet it is no longer in the accounts list, @@ -200,10 +201,22 @@ class SyncManager implements OnAccountsUpdatedListener { mSyncStorageEngine.doDatabaseCleanup(accounts); - if (hadAccountsAlready && accounts.length > 0) { - // request a sync so that if the password was changed we will - // retry any sync that failed when it was wrong - scheduleSync(null, null, null, 0 /* no delay */); + if (accounts.length > 0) { + // If this is the first time this was called after a bootup then + // the accounts haven't really changed, instead they were just loaded + // from the AccountManager. Otherwise at least one of the accounts + // has a change. + // + // If there was a real account change then force a sync of all accounts. + // This is a bit of overkill, but at least it will end up retrying syncs + // that failed due to an authentication failure and thus will recover if the + // account change was a password update. + // + // If this was the bootup case then don't sync everything, instead only + // sync those that have an unknown syncable state, which will give them + // a chance to set their syncable state. + boolean onlyThoseWithUnkownSyncableState = !justBootedUp; + scheduleSync(null, null, null, 0 /* no delay */, onlyThoseWithUnkownSyncableState); } } @@ -406,7 +419,7 @@ class SyncManager implements OnAccountsUpdatedListener { // perform a poll scheduleSync(null /* sync all syncable accounts */, null /* sync all syncable providers */, - new Bundle(), 0 /* no delay */); + new Bundle(), 0 /* no delay */, false /* onlyThoseWithUnkownSyncableState */); } private void writeSyncPollTime(long when) { @@ -508,9 +521,10 @@ class SyncManager implements OnAccountsUpdatedListener { * syncs of a specific provider. Can be null. Is ignored * if the url is null. * @param delay how many milliseconds in the future to wait before performing this + * @param onlyThoseWithUnkownSyncableState */ public void scheduleSync(Account requestedAccount, String requestedAuthority, - Bundle extras, long delay) { + Bundle extras, long delay, boolean onlyThoseWithUnkownSyncableState) { boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE); if (isLoggable) { Log.v(TAG, "scheduleSync:" @@ -596,14 +610,22 @@ class SyncManager implements OnAccountsUpdatedListener { for (String authority : syncableAuthorities) { for (Account account : accounts) { - boolean isSyncable = mSyncStorageEngine.getIsSyncable(account, authority) > 0; - if (!isSyncable) { + int isSyncable = mSyncStorageEngine.getIsSyncable(account, authority); + if (isSyncable == 0) { + continue; + } + if (onlyThoseWithUnkownSyncableState && isSyncable >= 0) { continue; } - if (mSyncAdapters.getServiceInfo(new SyncAdapterType(authority, account.type)) + if (mSyncAdapters.getServiceInfo(SyncAdapterType.newKey(authority, account.type)) != null) { + // make this an initialization sync if the isSyncable state is unknown + Bundle extrasCopy = new Bundle(extras); + if (isSyncable < 0) { + extrasCopy.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true); + } scheduleSyncOperation( - new SyncOperation(account, source, authority, extras, delay)); + new SyncOperation(account, source, authority, extrasCopy, delay)); } } } @@ -616,7 +638,8 @@ class SyncManager implements OnAccountsUpdatedListener { public void scheduleLocalSync(Account account, String authority) { final Bundle extras = new Bundle(); extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true); - scheduleSync(account, authority, extras, LOCAL_SYNC_DELAY); + scheduleSync(account, authority, extras, LOCAL_SYNC_DELAY, + false /* onlyThoseWithUnkownSyncableState */); } private IPackageManager getPackageManager() { @@ -1588,11 +1611,18 @@ class SyncManager implements OnAccountsUpdatedListener { final boolean syncAutomatically = mSyncStorageEngine.getSyncAutomatically(op.account, op.authority) && mSyncStorageEngine.getMasterSyncAutomatically(); - boolean isSyncable = - mSyncStorageEngine.getIsSyncable(op.account, op.authority) > 0; boolean syncAllowed = manualSync || (backgroundDataUsageAllowed && syncAutomatically); - if (!syncAllowed || !isSyncable) { + int isSyncable = mSyncStorageEngine.getIsSyncable(op.account, op.authority); + if (isSyncable == 0) { + // if not syncable, don't allow + syncAllowed = false; + } else if (isSyncable < 0) { + // if the syncable state is unknown, only allow initialization syncs + syncAllowed = + op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false); + } + if (!syncAllowed) { if (isLoggable) { Log.v(TAG, "runStateIdle: sync off, dropping " + op); } @@ -1636,8 +1666,7 @@ class SyncManager implements OnAccountsUpdatedListener { } // connect to the sync adapter - SyncAdapterType syncAdapterType = new SyncAdapterType(op.authority, - op.account.type); + SyncAdapterType syncAdapterType = SyncAdapterType.newKey(op.authority, op.account.type); RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterInfo = mSyncAdapters.getServiceInfo(syncAdapterType); if (syncAdapterInfo == null) { diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java index 264796281283..7f78e75b5699 100644 --- a/core/java/android/content/SyncStorageEngine.java +++ b/core/java/android/content/SyncStorageEngine.java @@ -162,8 +162,7 @@ public class SyncStorageEngine extends Handler { this.authority = authority; this.ident = ident; enabled = SYNC_ENABLED_DEFAULT; - // TODO: change the default to -1 when the syncadapters are changed to set this - syncable = 1; + syncable = -1; // default to "unknown" } } diff --git a/core/java/android/content/TempProviderSyncAdapter.java b/core/java/android/content/TempProviderSyncAdapter.java index fb05fe7807a5..b46c5454ac2f 100644 --- a/core/java/android/content/TempProviderSyncAdapter.java +++ b/core/java/android/content/TempProviderSyncAdapter.java @@ -13,6 +13,10 @@ import android.util.EventLog; import android.util.Log; import android.util.TimingLogger; import android.accounts.Account; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; + +import java.io.IOException; /** * @hide @@ -84,6 +88,9 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter { */ public abstract boolean isReadOnly(); + public abstract boolean getIsSyncable(Account account) + throws IOException, AuthenticatorException, OperationCanceledException; + /** * Get diffs from the server since the last completed sync and put them * into a temporary provider. @@ -173,6 +180,7 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter { private class SyncThread extends Thread { private final Account mAccount; + private final String mAuthority; private final Bundle mExtras; private final SyncContext mSyncContext; private volatile boolean mIsCanceled = false; @@ -180,9 +188,10 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter { private long mInitialRxBytes; private final SyncResult mResult; - SyncThread(SyncContext syncContext, Account account, Bundle extras) { + SyncThread(SyncContext syncContext, Account account, String authority, Bundle extras) { super("SyncThread"); mAccount = account; + mAuthority = authority; mExtras = extras; mSyncContext = syncContext; mResult = new SyncResult(); @@ -206,7 +215,7 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter { mInitialTxBytes = NetStat.getUidTxBytes(uid); mInitialRxBytes = NetStat.getUidRxBytes(uid); try { - sync(mSyncContext, mAccount, mExtras); + sync(mSyncContext, mAccount, mAuthority, mExtras); } catch (SQLException e) { Log.e(TAG, "Sync failed", e); mResult.databaseError = true; @@ -220,13 +229,39 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter { } } - private void sync(SyncContext syncContext, Account account, Bundle extras) { + private void sync(SyncContext syncContext, Account account, String authority, + Bundle extras) { mIsCanceled = false; mProviderSyncStarted = false; mAdapterSyncStarted = false; String message = null; + // always attempt to initialize if the isSyncable state isn't set yet + int isSyncable = ContentResolver.getIsSyncable(account, authority); + if (isSyncable < 0) { + try { + isSyncable = (getIsSyncable(account)) ? 1 : 0; + ContentResolver.setIsSyncable(account, authority, isSyncable); + } catch (IOException e) { + ++mResult.stats.numIoExceptions; + } catch (AuthenticatorException e) { + ++mResult.stats.numParseExceptions; + } catch (OperationCanceledException e) { + // do nothing + } + } + + // if this is an initialization request then our work is done here + if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) { + return; + } + + // if we aren't syncable then get out + if (isSyncable <= 0) { + return; + } + boolean manualSync = extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false); try { @@ -517,13 +552,14 @@ public abstract class TempProviderSyncAdapter extends SyncAdapter { EventLog.writeEvent(SyncAdapter.LOG_SYNC_DETAILS, TAG, bytesSent, bytesReceived, ""); } - public void startSync(SyncContext syncContext, Account account, Bundle extras) { + public void startSync(SyncContext syncContext, Account account, String authority, + Bundle extras) { if (mSyncThread != null) { syncContext.onFinished(SyncResult.ALREADY_IN_PROGRESS); return; } - mSyncThread = new SyncThread(syncContext, account, extras); + mSyncThread = new SyncThread(syncContext, account, authority, extras); mSyncThread.start(); } diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java index fab3f3d034f7..d57155c28441 100644 --- a/core/java/android/provider/Calendar.java +++ b/core/java/android/provider/Calendar.java @@ -473,6 +473,39 @@ public final class Calendar { * <P>Type: INTEGER (boolean)</P> */ public static final String HAS_ATTENDEE_DATA = "hasAttendeeData"; + + /** + * Whether guests can modify the event. + * <P>Type: INTEGER (boolean)</P> + */ + public static final String GUESTS_CAN_MODIFY = "guestsCanModify"; + + /** + * Whether guests can invite other guests. + * <P>Type: INTEGER (boolean)</P> + */ + public static final String GUESTS_CAN_INVITE_OTHERS = "guestsCanInviteOthers"; + + /** + * Whether guests can see the list of attendees. + * <P>Type: INTEGER (boolean)</P> + */ + public static final String GUESTS_CAN_SEE_GUESTS = "guestsCanSeeGuests"; + + /** + * Email of the organizer (owner) of the event. + * <P>Type: STRING</P> + */ + public static final String ORGANIZER = "organizer"; + + /** + * Whether the user can invite others to the event. + * The GUESTS_CAN_INVITE_OTHERS is a setting that applies to an arbitrary guest, + * while CAN_INVITE_OTHERS indicates if the user can invite others (either through + * GUESTS_CAN_INVITE_OTHERS or because the user has modify access to the event). + * <P>Type: INTEGER (boolean, readonly)</P> + */ + public static final String CAN_INVITE_OTHERS = "canInviteOthers"; } /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index d3e4c4c97ac5..18610959a5df 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3088,6 +3088,18 @@ public final class Settings { "vending_pd_resend_frequency_ms"; /** + * Size of buffer in bytes for Vending to use when reading cache files. + */ + public static final String VENDING_DISK_INPUT_BUFFER_BYTES = + "vending_disk_input_buffer_bytes"; + + /** + * Size of buffer in bytes for Vending to use when writing cache files. + */ + public static final String VENDING_DISK_OUTPUT_BUFFER_BYTES = + "vending_disk_output_buffer_bytes"; + + /** * Frequency in milliseconds at which we should cycle through the promoted applications * on the home screen or the categories page. */ diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index 4405a536b979..a6d76d684fe4 100755 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -61,7 +61,7 @@ public class TextToSpeech { /** - * Denotes the language is available exactly as specified by the locale + * Denotes the language is available exactly as specified by the locale. */ public static final int LANG_COUNTRY_VAR_AVAILABLE = 2; @@ -176,7 +176,7 @@ public class TextToSpeech { // intents to ask engine to install data or check its data /** - * Broadcast Action: Triggers the platform Text-To-Speech engine to + * Activity Action: Triggers the platform Text-To-Speech engine to * start the activity that installs the resource files on the device * that are required for TTS to be operational. Since the installation * of the data can be interrupted or declined by the user, the application @@ -184,18 +184,20 @@ public class TextToSpeech { * and if need be, should check installation status with * {@link #ACTION_CHECK_TTS_DATA}. */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_INSTALL_TTS_DATA = "android.speech.tts.engine.INSTALL_TTS_DATA"; /** - * {@hide} + * Broadcast Action: broadcast to signal the completion of the installation of + * the data files used by the synthesis engine. Success or failure is indicated in the + * {@link #EXTRA_TTS_DATA_INSTALLED} extra. */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_TTS_DATA_INSTALLED = "android.speech.tts.engine.TTS_DATA_INSTALLED"; /** - * Broadcast Action: Starts the activity from the platform Text-To-Speech + * Activity Action: Starts the activity from the platform Text-To-Speech * engine to verify the proper installation and availability of the * resource files on the system. Upon completion, the activity will * return one of the following codes: @@ -217,7 +219,7 @@ public class TextToSpeech { * and YYY is the 3-letter ISO country code.</li> * </ul> */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_CHECK_TTS_DATA = "android.speech.tts.engine.CHECK_TTS_DATA"; @@ -241,11 +243,11 @@ public class TextToSpeech { // extras for a TTS engine's data installation /** - * Extra information received with the {@link #ACTION_TTS_DATA_INSTALLED} intent - * which indicates whether the TTS data installation requested with - * {@link #ACTION_INSTALL_TTS_DATA} completed successfully or not. The value is - * {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}. - * {@hide} + * Extra information received with the {@link #ACTION_TTS_DATA_INSTALLED} intent. + * It indicates whether the data files for the synthesis engine were successfully + * installed. The installation was initiated with the {@link #ACTION_INSTALL_TTS_DATA} + * intent. The possible values for this extra are + * {@link TextToSpeech#SUCCESS} and {@link TextToSpeech#ERROR}. */ public static final String EXTRA_TTS_DATA_INSTALLED = "dataInstalled"; diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 3b780604d0dc..fe3f47f95561 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -686,7 +686,6 @@ public final class ViewRoot extends Handler implements ViewParent, attachInfo.mKeepScreenOn = false; viewVisibilityChanged = false; host.dispatchAttachedToWindow(attachInfo, 0); - getRunQueue().executeActions(attachInfo.mHandler); //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn); } else { @@ -719,6 +718,10 @@ public final class ViewRoot extends Handler implements ViewParent, boolean insetsChanged = false; if (mLayoutRequested) { + // Execute enqueued actions on every layout in case a view that was detached + // enqueued an action after being detached + getRunQueue().executeActions(attachInfo.mHandler); + if (mFirst) { host.fitSystemWindows(mAttachInfo.mContentInsets); // make sure touch mode code executes by setting cached value @@ -3142,7 +3145,7 @@ public final class ViewRoot extends Handler implements ViewParent, handler.postDelayed(handlerAction.action, handlerAction.delay); } - mActions.clear(); + actions.clear(); } } @@ -3156,7 +3159,6 @@ public final class ViewRoot extends Handler implements ViewParent, if (o == null || getClass() != o.getClass()) return false; HandlerAction that = (HandlerAction) o; - return !(action != null ? !action.equals(that.action) : that.action != null); } diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java index 21bcdf177217..ddc2da1f3938 100644 --- a/core/java/android/webkit/JWebCoreJavaBridge.java +++ b/core/java/android/webkit/JWebCoreJavaBridge.java @@ -90,7 +90,7 @@ final class JWebCoreJavaBridge extends Handler { break; case REFRESH_PLUGINS: nativeUpdatePluginDirectories(PluginManager.getInstance(null) - .getPluginDirecoties(), ((Boolean) msg.obj) + .getPluginDirectories(), ((Boolean) msg.obj) .booleanValue()); break; } @@ -182,7 +182,7 @@ final class JWebCoreJavaBridge extends Handler { * Returns an array of plugin directoies */ private String[] getPluginDirectories() { - return PluginManager.getInstance(null).getPluginDirecoties(); + return PluginManager.getInstance(null).getPluginDirectories(); } /** diff --git a/core/java/android/webkit/PluginManager.java b/core/java/android/webkit/PluginManager.java index cd341928bfcf..32eea5fcc95a 100644 --- a/core/java/android/webkit/PluginManager.java +++ b/core/java/android/webkit/PluginManager.java @@ -91,7 +91,7 @@ public class PluginManager { .sendToTarget(); } - String[] getPluginDirecoties() { + String[] getPluginDirectories() { ArrayList<String> directories = new ArrayList<String>(); PackageManager pm = mContext.getPackageManager(); List<ResolveInfo> plugins = pm.queryIntentServices(new Intent( @@ -147,6 +147,7 @@ public class PluginManager { } directories.add(directory); } + return directories.toArray(new String[directories.size()]); } diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 0720beb9cee8..dee62b41463a 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -1778,12 +1778,27 @@ final class WebViewCore { mBrowserFrame.didFirstLayout(); - // reset the scroll position as it is a new page now - mWebkitScrollX = mWebkitScrollY = 0; + if (mWebView == null) return; + + setupViewport(standardLoad || mRestoredScale > 0); + + // reset the scroll position, the restored offset and scales + mWebkitScrollX = mWebkitScrollY = mRestoredX = mRestoredY + = mRestoredScale = mRestoredScreenWidthScale = 0; + } - // for non-standard load, we only adjust scale if mRestoredScale > 0 - if (mWebView == null || (mRestoredScale == 0 && !standardLoad)) return; + // called by JNI + private void updateViewport() { + // if updateViewport is called before first layout, wait until first + // layout to update the viewport. In the rare case, this is called after + // first layout, force an update as we have just parsed the viewport + // meta tag. + if (mBrowserFrame.firstLayoutDone()) { + setupViewport(true); + } + } + private void setupViewport(boolean updateRestoreState) { // set the viewport settings from WebKit setViewportSettingsFromNative(); @@ -1834,6 +1849,9 @@ final class WebViewCore { mViewportWidth = 0; } + // if mViewportWidth is 0, it means device-width, always update. + if (mViewportWidth != 0 && !updateRestoreState) return; + // now notify webview int webViewWidth = Math.round(mCurrentViewWidth * mCurrentViewScale); mRestoreState = new RestoreState(); @@ -1884,25 +1902,29 @@ final class WebViewCore { data.mScale = -1.0f; mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null, EventHub.VIEW_SIZE_CHANGED, data)); - } else if (mSettings.getUseWideViewPort() && mCurrentViewWidth > 0) { - WebView.ViewSizeData data = new WebView.ViewSizeData(); - // mViewScale as 0 means it is in zoom overview mode. So we don't - // know the exact scale. If mRestoredScale is non-zero, use it; - // otherwise just use mTextWrapScale as the initial scale. - data.mScale = mRestoreState.mViewScale == 0 - ? (mRestoredScale > 0 ? mRestoredScale - : mRestoreState.mTextWrapScale) - : mRestoreState.mViewScale; - data.mWidth = Math.round(webViewWidth / data.mScale); - data.mHeight = mCurrentViewHeight * data.mWidth - / mCurrentViewWidth; - data.mTextWrapWidth = Math.round(webViewWidth - / mRestoreState.mTextWrapScale); - mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null, - EventHub.VIEW_SIZE_CHANGED, data)); + } else if (mSettings.getUseWideViewPort()) { + if (mCurrentViewWidth == 0) { + // Trick to ensure VIEW_SIZE_CHANGED will be sent from WebView + // to WebViewCore + mWebView.mLastWidthSent = 0; + } else { + WebView.ViewSizeData data = new WebView.ViewSizeData(); + // mViewScale as 0 means it is in zoom overview mode. So we don't + // know the exact scale. If mRestoredScale is non-zero, use it; + // otherwise just use mTextWrapScale as the initial scale. + data.mScale = mRestoreState.mViewScale == 0 + ? (mRestoredScale > 0 ? mRestoredScale + : mRestoreState.mTextWrapScale) + : mRestoreState.mViewScale; + data.mWidth = Math.round(webViewWidth / data.mScale); + data.mHeight = mCurrentViewHeight * data.mWidth + / mCurrentViewWidth; + data.mTextWrapWidth = Math.round(webViewWidth + / mRestoreState.mTextWrapScale); + mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null, + EventHub.VIEW_SIZE_CHANGED, data)); + } } - // reset restored offset, scale - mRestoredX = mRestoredY = mRestoredScale = mRestoredScreenWidthScale = 0; } // called by JNI diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 608c1ff6ee0d..35042f1d842a 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -49,7 +49,6 @@ <protected-broadcast android:name="android.intent.action.ACTION_SHUTDOWN" /> <protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_LOW" /> <protected-broadcast android:name="android.intent.action.DEVICE_STORAGE_OK" /> - <protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" /> <protected-broadcast android:name="android.intent.action.NEW_OUTGOING_CALL" /> <protected-broadcast android:name="android.intent.action.REBOOT" /> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 01253d330e26..eee87e697276 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -361,7 +361,7 @@ <!-- Small inverse ProgressBar style. This is a small circular progress bar. --> <attr name="progressBarStyleSmallInverse" format="reference" /> <!-- Large inverse ProgressBar style. This is a large circular progress bar. --> - <attr name="progressBarStyleLargeInverse" format="reference" /> + <attr name="progressBarStyleLargeInverse" format="reference" /> <!-- Default SeekBar style. --> <attr name="seekBarStyle" format="reference" /> <!-- Default RatingBar style. --> @@ -2348,7 +2348,7 @@ <attr name="pivotY" /> <attr name="drawable" /> </declare-styleable> - + <declare-styleable name="InsetDrawable"> <attr name="visible" /> <attr name="drawable" /> @@ -2886,7 +2886,7 @@ results for "bo", it would not be queried again for "bob". The default value is <code>false</code>. <i>Optional attribute.</i>. --> <attr name="queryAfterZeroResults" format="boolean" /> - + <!-- If provided, this string will be used to describe the searchable item in the searchable items settings within system search settings. <i>Optional attribute.</i> --> @@ -3359,6 +3359,7 @@ <!-- the authority of a content provider. --> <attr name="contentAuthority" format="string"/> <attr name="accountType"/> + <attr name="userVisible" format="boolean"/> </declare-styleable> <!-- =============================== --> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index d51b4399705f..60b492a61134 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1130,17 +1130,17 @@ <public type="style" name="Widget.ProgressBar.Inverse" id="0x0103005b" /> <public type="style" name="Widget.ProgressBar.Large.Inverse" id="0x0103005c" /> - <public type="style" name="Widget.ProgressBar.Small.Inverse" id="0x0103005d" /> + <public type="style" name="Widget.ProgressBar.Small.Inverse" id="0x0103005d" /> <public type="drawable" name="stat_sys_vp_phone_call" id="0x010800a7" /> <public type="drawable" name="stat_sys_vp_phone_call_on_hold" id="0x010800a8" /> - + <public type="anim" name="anticipate_interpolator" id="0x010a0007" /> <public type="anim" name="overshoot_interpolator" id="0x010a0008" /> <public type="anim" name="anticipate_overshoot_interpolator" id="0x010a0009" /> <public type="anim" name="bounce_interpolator" id="0x010a000a" /> <public type="anim" name="linear_interpolator" id="0x010a000b" /> - + <!-- =============================================================== Resources added in Eclair. =============================================================== --> @@ -1148,6 +1148,7 @@ <public type="attr" name="accountType" /> <public type="attr" name="contentAuthority" /> + <public type="attr" name="userVisible" /> <public type="attr" name="windowShowWallpaper" /> <public type="style" name="Theme.Wallpaper" /> diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk index ecd3b2e7dfac..46affe7e2296 100644 --- a/media/libstagefright/omx/Android.mk +++ b/media/libstagefright/omx/Android.mk @@ -15,11 +15,15 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libbinder \ libmedia \ - libutils \ + libutils \ libui \ libcutils \ libopencore_common +ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true) + LOCAL_LDLIBS += -lpthread +endif + LOCAL_PRELINK_MODULE:= false LOCAL_MODULE:= libstagefright_omx diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index c0ae592f6692..76a5acdb4c6f 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -323,6 +323,7 @@ enum { LABEL_ATTR = 0x01010001, ICON_ATTR = 0x01010002, MIN_SDK_VERSION_ATTR = 0x0101020c, + MAX_SDK_VERSION_ATTR = 0x01010271, REQ_TOUCH_SCREEN_ATTR = 0x01010227, REQ_KEYBOARD_TYPE_ATTR = 0x01010228, REQ_HARD_KEYBOARD_ATTR = 0x01010229, @@ -587,6 +588,10 @@ int doDump(Bundle* bundle) targetSdk = code; printf("sdkVersion:'%d'\n", code); } + code = getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR, NULL, -1); + if (code != -1) { + printf("maxSdkVersion:'%d'\n", code); + } code = getIntegerAttribute(tree, TARGET_SDK_VERSION_ATTR, &error); if (error != "") { error = ""; diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap.java index 6bc01b129df5..7dde63446e08 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Bitmap.java +++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap.java @@ -16,7 +16,6 @@ package android.graphics; -import com.android.layoutlib.bridge.BridgeCanvas; import java.awt.image.BufferedImage; import java.io.File; @@ -25,15 +24,15 @@ import java.io.IOException; import javax.imageio.ImageIO; public final class Bitmap extends _Original_Bitmap { - + private BufferedImage mImage; public Bitmap(File input) throws IOException { super(1, true, null); - + mImage = ImageIO.read(input); } - + Bitmap(BufferedImage image) { super(1, true, null); mImage = image; @@ -42,9 +41,9 @@ public final class Bitmap extends _Original_Bitmap { public BufferedImage getImage() { return mImage; } - + // ----- overriden methods - + public enum Config { // these native values must match up with the enum in SkBitmap.h ALPHA_8 (2), @@ -56,27 +55,26 @@ public final class Bitmap extends _Original_Bitmap { this.nativeInt = ni; } final int nativeInt; - + /* package */ static Config nativeToConfig(int ni) { return sConfigs[ni]; } - + private static Config sConfigs[] = { null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888 }; } - @Override public int getWidth() { return mImage.getWidth(); } - + @Override public int getHeight() { return mImage.getHeight(); } - + /** * Returns an immutable bitmap from the source bitmap. The new bitmap may * be the same object as source, or a copy may have been made. @@ -100,7 +98,7 @@ public final class Bitmap extends _Original_Bitmap { int width, int height) { return new Bitmap(source.mImage.getSubimage(x, y, width, height)); } - + /** * Returns an immutable bitmap from subset of the source bitmap, * transformed by the optional matrix. @@ -158,7 +156,7 @@ public final class Bitmap extends _Original_Bitmap { neww = Math.round(deviceR.width()); newh = Math.round(deviceR.height()); - BridgeCanvas canvas = new BridgeCanvas(neww, newh); + Canvas canvas = new Canvas(neww, newh); canvas.translate(-deviceR.left, -deviceR.top); canvas.concat(m); @@ -169,10 +167,10 @@ public final class Bitmap extends _Original_Bitmap { } canvas.drawBitmap(source, srcR, dstR, paint); - + return new Bitmap(canvas.getImage()); } - + /** * Returns a mutable bitmap with the specified width and height. * @@ -184,7 +182,7 @@ public final class Bitmap extends _Original_Bitmap { public static Bitmap createBitmap(int width, int height, Config config) { return new Bitmap(new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)); } - + /** * Returns a immutable bitmap with the specified width and height, with each * pixel value set to the corresponding value in the colors array. @@ -215,7 +213,7 @@ public final class Bitmap extends _Original_Bitmap { || (lastScanline + width > length)) { throw new ArrayIndexOutOfBoundsException(); } - + // TODO: create an immutable bitmap... throw new UnsupportedOperationException(); } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeCanvas.java b/tools/layoutlib/bridge/src/android/graphics/Canvas.java index 47106912e467..3fa1d1d6cf0c 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeCanvas.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas.java @@ -14,24 +14,16 @@ * limitations under the License. */ -package com.android.layoutlib.bridge; +package android.graphics; import com.android.layoutlib.api.ILayoutLog; -import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.DrawFilter; -import android.graphics.LinearGradient; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Path; import android.graphics.Picture; import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; -import android.graphics.Shader; import android.graphics.Xfermode; import android.graphics.Paint.Align; import android.graphics.Paint.Style; @@ -43,6 +35,7 @@ import java.awt.Composite; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.RenderingHints; +import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.util.Stack; @@ -51,36 +44,59 @@ import javax.microedition.khronos.opengles.GL; /** * Re-implementation of the Canvas, 100% in java on top of a BufferedImage. */ -public class BridgeCanvas extends Canvas { - +public class Canvas extends _Original_Canvas { + private BufferedImage mBufferedImage; private final Stack<Graphics2D> mGraphicsStack = new Stack<Graphics2D>(); private final ILayoutLog mLogger; - public BridgeCanvas(int width, int height, ILayoutLog logger) { + public Canvas() { + mLogger = null; + // the mBufferedImage will be taken from a bitmap in #setBitmap() + } + + public Canvas(Bitmap bitmap) { + mLogger = null; + mBufferedImage = bitmap.getImage(); + mGraphicsStack.push(mBufferedImage.createGraphics()); + } + + public Canvas(int nativeCanvas) { + mLogger = null; + throw new UnsupportedOperationException("Can't create Canvas(int)"); + } + + public Canvas(javax.microedition.khronos.opengles.GL gl) { + mLogger = null; + throw new UnsupportedOperationException("Can't create Canvas(javax.microedition.khronos.opengles.GL)"); + } + + // custom constructors for our use. + public Canvas(int width, int height, ILayoutLog logger) { mLogger = logger; mBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); mGraphicsStack.push(mBufferedImage.createGraphics()); } - - public BridgeCanvas(int width, int height) { + + public Canvas(int width, int height) { this(width, height, null /* logger*/); } - + + // custom mehtods public BufferedImage getImage() { return mBufferedImage; } - - Graphics2D getGraphics2d() { + + public Graphics2D getGraphics2d() { return mGraphicsStack.peek(); } - - void dispose() { + + public void dispose() { while (mGraphicsStack.size() > 0) { mGraphicsStack.pop().dispose(); } } - + /** * Creates a new {@link Graphics2D} based on the {@link Paint} parameters. * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used. @@ -91,11 +107,11 @@ public class BridgeCanvas extends Canvas { g.setColor(new Color(paint.getColor())); int alpha = paint.getAlpha(); float falpha = alpha / 255.f; - + Xfermode xfermode = paint.getXfermode(); if (xfermode instanceof PorterDuffXfermode) { PorterDuff.Mode mode = ((PorterDuffXfermode)xfermode).getMode(); - + setModeInGraphics(mode, g, falpha); } else { if (mLogger != null && xfermode != null) { @@ -105,7 +121,7 @@ public class BridgeCanvas extends Canvas { } g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha)); } - + Shader shader = paint.getShader(); if (shader instanceof LinearGradient) { g.setPaint(((LinearGradient)shader).getPaint()); @@ -116,10 +132,10 @@ public class BridgeCanvas extends Canvas { shader.getClass().getCanonicalName())); } } - + return g; } - + private void setModeInGraphics(PorterDuff.Mode mode, Graphics2D g, float falpha) { switch (mode) { case CLEAR: @@ -168,14 +184,43 @@ public class BridgeCanvas extends Canvas { break; } } - + + + // -------------------- + // OVERRIDEN ENUMS + // This is needed since we rename Canvas into _Original_Canvas + // -------------------- + + public enum EdgeType { + BW(0), //!< treat edges by just rounding to nearest pixel boundary + AA(1); //!< treat edges by rounding-out, since they may be antialiased + + EdgeType(int nativeInt) { + this.nativeInt = nativeInt; + } + final int nativeInt; + } + + // -------------------- - + // OVERRIDEN METHODS + // -------------------- + @Override public void finalize() throws Throwable { // pass } - + + /* (non-Javadoc) + * @see android.graphics.Canvas#setBitmap(android.graphics.Bitmap) + */ + @Override + public void setBitmap(Bitmap bitmap) { + mBufferedImage = bitmap.getImage(); + mGraphicsStack.push(mBufferedImage.createGraphics()); + } + + /* (non-Javadoc) * @see android.graphics.Canvas#translate(float, float) */ @@ -183,7 +228,7 @@ public class BridgeCanvas extends Canvas { public void translate(float dx, float dy) { getGraphics2d().translate(dx, dy); } - + /* (non-Javadoc) * @see android.graphics.Canvas#save() */ @@ -191,7 +236,7 @@ public class BridgeCanvas extends Canvas { public int save() { Graphics2D g = (Graphics2D)getGraphics2d().create(); mGraphicsStack.push(g); - + return mGraphicsStack.size() - 1; } @@ -203,7 +248,7 @@ public class BridgeCanvas extends Canvas { // For now we ignore saveFlags return save(); } - + /* (non-Javadoc) * @see android.graphics.Canvas#restore() */ @@ -221,7 +266,7 @@ public class BridgeCanvas extends Canvas { mGraphicsStack.pop(); } } - + /* (non-Javadoc) * @see android.graphics.Canvas#getSaveCount() */ @@ -229,8 +274,8 @@ public class BridgeCanvas extends Canvas { public int getSaveCount() { return mGraphicsStack.size() - 1; } - - + + /* (non-Javadoc) * @see android.graphics.Canvas#clipRect(float, float, float, float, android.graphics.Region.Op) */ @@ -288,23 +333,36 @@ public class BridgeCanvas extends Canvas { public boolean clipRect(RectF rect) { return clipRect(rect.left, rect.top, rect.right, rect.bottom); } - - @Override + public boolean quickReject(RectF rect, EdgeType type) { return false; } @Override + public boolean quickReject(RectF rect, _Original_Canvas.EdgeType type) { + throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); + } + public boolean quickReject(Path path, EdgeType type) { return false; } @Override + public boolean quickReject(Path path, _Original_Canvas.EdgeType type) { + throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); + } + public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) { return false; } + @Override + public boolean quickReject(float left, float top, float right, float bottom, + _Original_Canvas.EdgeType type) { + throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN"); + } + /** * Retrieve the clip bounds, returning true if they are non-empty. * @@ -324,31 +382,31 @@ public class BridgeCanvas extends Canvas { } return false; } - + /* (non-Javadoc) * @see android.graphics.Canvas#drawColor(int, android.graphics.PorterDuff.Mode) */ @Override public void drawColor(int color, PorterDuff.Mode mode) { Graphics2D g = getGraphics2d(); - + // save old color Color c = g.getColor(); - + Composite composite = g.getComposite(); - + // get the alpha from the color int alpha = color >>> 24; float falpha = alpha / 255.f; - + setModeInGraphics(mode, g, falpha); - + g.setColor(new Color(color)); - + getGraphics2d().fillRect(0, 0, getWidth(), getHeight()); - + g.setComposite(composite); - + // restore color g.setColor(c); } @@ -360,7 +418,7 @@ public class BridgeCanvas extends Canvas { public void drawColor(int color) { drawColor(color, PorterDuff.Mode.SRC_OVER); } - + /* (non-Javadoc) * @see android.graphics.Canvas#drawARGB(int, int, int, int) */ @@ -368,7 +426,7 @@ public class BridgeCanvas extends Canvas { public void drawARGB(int a, int r, int g, int b) { drawColor(a << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER); } - + /* (non-Javadoc) * @see android.graphics.Canvas#drawRGB(int, int, int) */ @@ -377,7 +435,7 @@ public class BridgeCanvas extends Canvas { drawColor(0xFF << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER); } - + /* (non-Javadoc) * @see android.graphics.Canvas#getWidth() */ @@ -385,7 +443,7 @@ public class BridgeCanvas extends Canvas { public int getWidth() { return mBufferedImage.getWidth(); } - + /* (non-Javadoc) * @see android.graphics.Canvas#getHeight() */ @@ -401,7 +459,7 @@ public class BridgeCanvas extends Canvas { public void drawPaint(Paint paint) { drawColor(paint.getColor()); } - + /* (non-Javadoc) * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint) */ @@ -417,7 +475,32 @@ public class BridgeCanvas extends Canvas { */ @Override public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) { - throw new UnsupportedOperationException(); + boolean needsRestore = false; + if (matrix.isIdentity() == false) { + // create a new graphics and apply the matrix to it + save(); // this creates a new Graphics2D, and stores it for children call to use + needsRestore = true; + Graphics2D g = getGraphics2d(); // get the newly create Graphics2D + + // get the Graphics2D current matrix + AffineTransform currentTx = g.getTransform(); + // get the AffineTransform from the matrix + AffineTransform matrixTx = matrix.getTransform(); + + // combine them so that the matrix is applied after. + currentTx.preConcatenate(matrixTx); + + // give it to the graphics as a new matrix replacing all previous transform + g.setTransform(currentTx); + } + + // draw the bitmap + drawBitmap(bitmap, 0, 0, paint); + + if (needsRestore) { + // remove the new graphics + restore(); + } } /* (non-Javadoc) @@ -456,39 +539,42 @@ public class BridgeCanvas extends Canvas { int height, boolean hasAlpha, Paint paint) { throw new UnsupportedOperationException(); } - + private void drawBitmap(Bitmap bitmap, int sleft, int stop, int sright, int sbottom, int dleft, int dtop, int dright, int dbottom, Paint paint) { BufferedImage image = bitmap.getImage(); - + Graphics2D g = getGraphics2d(); - + Composite c = null; - - if (paint.isFilterBitmap()) { - g = (Graphics2D)g.create(); - g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, - RenderingHints.VALUE_INTERPOLATION_BILINEAR); - } - - if (paint.getAlpha() != 0xFF) { - c = g.getComposite(); - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, - paint.getAlpha()/255.f)); + + if (paint != null) { + if (paint.isFilterBitmap()) { + g = (Graphics2D)g.create(); + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BILINEAR); + } + + if (paint.getAlpha() != 0xFF) { + c = g.getComposite(); + g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, + paint.getAlpha()/255.f)); + } } - + g.drawImage(image, dleft, dtop, dright, dbottom, sleft, stop, sright, sbottom, null); - if (paint.isFilterBitmap()) { - g.dispose(); - } - - if (c != null) { - g.setComposite(c); + if (paint != null) { + if (paint.isFilterBitmap()) { + g.dispose(); + } + if (c != null) { + g.setComposite(c); + } } } - + /* (non-Javadoc) * @see android.graphics.Canvas#rotate(float, float, float) */ @@ -509,7 +595,7 @@ public class BridgeCanvas extends Canvas { public void rotate(float degrees) { getGraphics2d().rotate(Math.toRadians(degrees)); } - + /* (non-Javadoc) * @see android.graphics.Canvas#scale(float, float, float, float) */ @@ -528,19 +614,19 @@ public class BridgeCanvas extends Canvas { public void scale(float sx, float sy) { getGraphics2d().scale(sx, sy); } - + /* (non-Javadoc) * @see android.graphics.Canvas#drawText(char[], int, int, float, float, android.graphics.Paint) */ @Override public void drawText(char[] text, int index, int count, float x, float y, Paint paint) { Graphics2D g = getGraphics2d(); - + g = (Graphics2D)g.create(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - + g.setFont(paint.getFont()); - + // set the color. because this only handles RGB we have to handle the alpha separately g.setColor(new Color(paint.getColor())); int alpha = paint.getAlpha(); @@ -557,9 +643,9 @@ public class BridgeCanvas extends Canvas { x -= m; } } - + g.drawChars(text, index, count, (int)x, (int)y); - + g.dispose(); } @@ -586,7 +672,7 @@ public class BridgeCanvas extends Canvas { public void drawText(String text, int start, int end, float x, float y, Paint paint) { drawText(text.toCharArray(), start, end - start, x, y, paint); } - + /* (non-Javadoc) * @see android.graphics.Canvas#drawRect(android.graphics.RectF, android.graphics.Paint) */ @@ -594,7 +680,7 @@ public class BridgeCanvas extends Canvas { public void drawRect(RectF rect, Paint paint) { doDrawRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), paint); } - + /* (non-Javadoc) * @see android.graphics.Canvas#drawRect(float, float, float, float, android.graphics.Paint) */ @@ -614,11 +700,11 @@ public class BridgeCanvas extends Canvas { private final void doDrawRect(int left, int top, int width, int height, Paint paint) { // get current graphisc Graphics2D g = getGraphics2d(); - + g = getNewGraphics(paint, g); Style style = paint.getStyle(); - + // draw if (style == Style.FILL || style == Style.FILL_AND_STROKE) { g.fillRect(left, top, width, height); @@ -639,16 +725,16 @@ public class BridgeCanvas extends Canvas { public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) { // get current graphisc Graphics2D g = getGraphics2d(); - + g = getNewGraphics(paint, g); Style style = paint.getStyle(); - + // draw - + int arcWidth = (int)(rx * 2); int arcHeight = (int)(ry * 2); - + if (style == Style.FILL || style == Style.FILL_AND_STROKE) { g.fillRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), arcWidth, arcHeight); @@ -671,7 +757,7 @@ public class BridgeCanvas extends Canvas { public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) { // get current graphisc Graphics2D g = getGraphics2d(); - + g = getNewGraphics(paint, g); g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY); @@ -679,7 +765,7 @@ public class BridgeCanvas extends Canvas { // dispose Graphics2D object g.dispose(); } - + /* (non-Javadoc) * @see android.graphics.Canvas#drawLines(float[], int, int, android.graphics.Paint) */ @@ -687,7 +773,7 @@ public class BridgeCanvas extends Canvas { public void drawLines(float[] pts, int offset, int count, Paint paint) { // get current graphisc Graphics2D g = getGraphics2d(); - + g = getNewGraphics(paint, g); for (int i = 0 ; i < count ; i += 4) { @@ -706,7 +792,7 @@ public class BridgeCanvas extends Canvas { public void drawLines(float[] pts, Paint paint) { drawLines(pts, 0, pts.length, paint); } - + /* (non-Javadoc) * @see android.graphics.Canvas#drawCircle(float, float, float, android.graphics.Paint) */ @@ -714,11 +800,11 @@ public class BridgeCanvas extends Canvas { public void drawCircle(float cx, float cy, float radius, Paint paint) { // get current graphisc Graphics2D g = getGraphics2d(); - + g = getNewGraphics(paint, g); Style style = paint.getStyle(); - + int size = (int)(radius * 2); // draw @@ -741,11 +827,11 @@ public class BridgeCanvas extends Canvas { public void drawOval(RectF oval, Paint paint) { // get current graphics Graphics2D g = getGraphics2d(); - + g = getNewGraphics(paint, g); Style style = paint.getStyle(); - + // draw if (style == Style.FILL || style == Style.FILL_AND_STROKE) { g.fillOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height()); @@ -758,7 +844,7 @@ public class BridgeCanvas extends Canvas { // dispose Graphics2D object g.dispose(); } - + /* (non-Javadoc) * @see android.graphics.Canvas#drawPath(android.graphics.Path, android.graphics.Paint) */ @@ -766,11 +852,11 @@ public class BridgeCanvas extends Canvas { public void drawPath(Path path, Paint paint) { // get current graphics Graphics2D g = getGraphics2d(); - + g = getNewGraphics(paint, g); Style style = paint.getStyle(); - + // draw if (style == Style.FILL || style == Style.FILL_AND_STROKE) { g.fill(path.getAwtShape()); @@ -783,7 +869,7 @@ public class BridgeCanvas extends Canvas { // dispose Graphics2D object g.dispose(); } - + /* (non-Javadoc) * @see android.graphics.Canvas#setMatrix(android.graphics.Matrix) */ @@ -795,10 +881,10 @@ public class BridgeCanvas extends Canvas { // get the new current graphics Graphics2D g = getGraphics2d(); - + // and apply the matrix g.setTransform(matrix.getTransform()); - + if (mLogger != null && matrix.hasPerspective()) { mLogger.warning("android.graphics.Canvas#setMatrix(android.graphics.Matrix) only supports affine transformations in the Layout Editor."); } @@ -1059,15 +1145,6 @@ public class BridgeCanvas extends Canvas { } /* (non-Javadoc) - * @see android.graphics.Canvas#setBitmap(android.graphics.Bitmap) - */ - @Override - public void setBitmap(Bitmap bitmap) { - // TODO Auto-generated method stub - super.setBitmap(bitmap); - } - - /* (non-Javadoc) * @see android.graphics.Canvas#setDrawFilter(android.graphics.DrawFilter) */ @Override diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix.java b/tools/layoutlib/bridge/src/android/graphics/Matrix.java index 18c0e178b3b7..3974e08f18cc 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Matrix.java +++ b/tools/layoutlib/bridge/src/android/graphics/Matrix.java @@ -17,6 +17,7 @@ package android.graphics; import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; /** @@ -747,7 +748,24 @@ public class Matrix extends _Original_Matrix { * inverted, ignore inverse and return false. */ public boolean invert(Matrix inverse) { - throw new UnsupportedOperationException("STUB NEEDED"); + if (inverse == null) { + return false; + } + + try { + AffineTransform affineTransform = getTransform(); + AffineTransform inverseTransform = affineTransform.createInverse(); + inverse.mValues[0] = (float)inverseTransform.getScaleX(); + inverse.mValues[1] = (float)inverseTransform.getShearX(); + inverse.mValues[2] = (float)inverseTransform.getTranslateX(); + inverse.mValues[3] = (float)inverseTransform.getScaleX(); + inverse.mValues[4] = (float)inverseTransform.getShearY(); + inverse.mValues[5] = (float)inverseTransform.getTranslateY(); + + return true; + } catch (NoninvertibleTransformException e) { + return false; + } } @Override @@ -770,7 +788,19 @@ public class Matrix extends _Original_Matrix { public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex, int pointCount) { checkPointArrays(src, srcIndex, dst, dstIndex, pointCount); - throw new UnsupportedOperationException("STUB NEEDED"); + + for (int i = 0 ; i < pointCount ; i++) { + // just in case we are doing in place, we better put this in temp vars + float x = mValues[0] * src[i + srcIndex] + + mValues[1] * src[i + srcIndex + 1] + + mValues[2]; + float y = mValues[3] * src[i + srcIndex] + + mValues[4] * src[i + srcIndex + 1] + + mValues[5]; + + dst[i + dstIndex] = x; + dst[i + dstIndex + 1] = y; + } } /** @@ -858,7 +888,26 @@ public class Matrix extends _Original_Matrix { if (dst == null || src == null) { throw new NullPointerException(); } - throw new UnsupportedOperationException("STUB NEEDED"); + + // array with 4 corners + float[] corners = new float[] { + src.left, src.top, + src.right, src.top, + src.right, src.bottom, + src.left, src.bottom, + }; + + // apply the transform to them. + mapPoints(corners); + + // now put the result in the rect. We take the min/max of Xs and min/max of Ys + dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6])); + dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6])); + + dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7])); + dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7])); + + return rectStaysRect(); } /** diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index c5981267c5dc..6e26a05543cc 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -31,6 +31,7 @@ import com.android.tools.layoutlib.create.MethodAdapter; import com.android.tools.layoutlib.create.OverrideMethod; import android.graphics.Bitmap; +import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.Region; import android.graphics.Typeface; @@ -401,8 +402,7 @@ public final class Bridge implements ILayoutBridge { view.layout(0, screenOffset, screenWidth, screenHeight); // draw them - BridgeCanvas canvas = new BridgeCanvas(screenWidth, screenHeight - screenOffset, - logger); + Canvas canvas = new Canvas(screenWidth, screenHeight - screenOffset, logger); root.draw(canvas); canvas.dispose(); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java index 5f0852e3bf03..abbf2f0546c1 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java @@ -30,17 +30,17 @@ public class NinePatchDrawable extends Drawable { NinePatchDrawable(NinePatch ninePatch) { m9Patch = ninePatch; } - + @Override public int getMinimumWidth() { return m9Patch.getWidth(); } - + @Override public int getMinimumHeight() { return m9Patch.getHeight(); } - + /** * Return the intrinsic width of the underlying drawable object. Returns * -1 if it has no intrinsic width, such as with a solid color. @@ -58,7 +58,7 @@ public class NinePatchDrawable extends Drawable { public int getIntrinsicHeight() { return m9Patch.getHeight(); } - + /** * Return in padding the insets suggested by this Drawable for placing * content inside the drawable's bounds. Positive values move toward the @@ -76,24 +76,18 @@ public class NinePatchDrawable extends Drawable { padding.bottom = padd[3]; return true; } - + @Override public void draw(Canvas canvas) { - if (canvas instanceof BridgeCanvas) { - BridgeCanvas bridgeCanvas = (BridgeCanvas)canvas; - - Rect r = getBounds(); - m9Patch.draw(bridgeCanvas.getGraphics2d(), r.left, r.top, r.width(), r.height()); - - return; - } - - throw new UnsupportedOperationException(); + Rect r = getBounds(); + m9Patch.draw(canvas.getGraphics2d(), r.left, r.top, r.width(), r.height()); + + return; } - + // ----------- Not implemented methods --------------- - + @Override public int getOpacity() { diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java index c07baffe0b54..47184f10efdc 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java @@ -54,18 +54,19 @@ public class Main { }, new String[] { // classes to rename (so that we can replace them in layoutlib) // original-platform-class-name ======> renamed-class-name + "android.graphics.Bitmap", "android.graphics._Original_Bitmap", + "android.graphics.BitmapShader", "android.graphics._Original_BitmapShader", + "android.graphics.Canvas", "android.graphics._Original_Canvas", + "android.graphics.ComposeShader", "android.graphics._Original_ComposeShader", + "android.graphics.LinearGradient", "android.graphics._Original_LinearGradient", "android.graphics.Matrix", "android.graphics._Original_Matrix", "android.graphics.Paint", "android.graphics._Original_Paint", - "android.graphics.Typeface", "android.graphics._Original_Typeface", - "android.graphics.Bitmap", "android.graphics._Original_Bitmap", "android.graphics.Path", "android.graphics._Original_Path", "android.graphics.PorterDuffXfermode", "android.graphics._Original_PorterDuffXfermode", - "android.graphics.Shader", "android.graphics._Original_Shader", - "android.graphics.LinearGradient", "android.graphics._Original_LinearGradient", - "android.graphics.BitmapShader", "android.graphics._Original_BitmapShader", - "android.graphics.ComposeShader", "android.graphics._Original_ComposeShader", "android.graphics.RadialGradient", "android.graphics._Original_RadialGradient", + "android.graphics.Shader", "android.graphics._Original_Shader", "android.graphics.SweepGradient", "android.graphics._Original_SweepGradient", + "android.graphics.Typeface", "android.graphics._Original_Typeface", "android.os.ServiceManager", "android.os._Original_ServiceManager", "android.util.FloatMath", "android.util._Original_FloatMath", "android.view.SurfaceView", "android.view._Original_SurfaceView", |