169c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackbornpackage android.app.assist; 269c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn 316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackbornimport android.content.ClipData; 469c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackbornimport android.content.Intent; 516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackbornimport android.net.Uri; 616036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackbornimport android.os.Bundle; 769c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackbornimport android.os.Parcel; 869c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackbornimport android.os.Parcelable; 969c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn 1069c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn/** 1116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * Holds information about the content an application is viewing, to hand to an 1216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * assistant at the user's request. This is filled in by 1316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}. 1469c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn */ 1516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackbornpublic class AssistContent implements Parcelable { 1616036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn private boolean mIsAppProvidedIntent = false; 17dfc23dd185d291c796f2939e4f8be0a8efc17ccbDianne Hackborn private boolean mIsAppProvidedWebUri = false; 1816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn private Intent mIntent; 1916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn private String mStructuredData; 2016036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn private ClipData mClipData; 2116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn private Uri mUri; 2216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn private final Bundle mExtras; 2369c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn 2469c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn public AssistContent() { 2516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mExtras = new Bundle(); 2669c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn } 2769c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn 2816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn /** 2916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * @hide 3016036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * Called by {@link android.app.ActivityThread} to set the default Intent based on 3116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * {@link android.app.Activity#getIntent Activity.getIntent}. 3216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * 3316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * <p>Automatically populates {@link #mUri} if that Intent is an {@link Intent#ACTION_VIEW} 3416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * of a web (http or https scheme) URI.</p> 3516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn */ 3616036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn public void setDefaultIntent(Intent intent) { 3716036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mIntent = intent; 38a5381085d399bd7e78a5f8df4a3e5e74ee90676dAdam Skory mIsAppProvidedIntent = false; 39a5381085d399bd7e78a5f8df4a3e5e74ee90676dAdam Skory mIsAppProvidedWebUri = false; 40a5381085d399bd7e78a5f8df4a3e5e74ee90676dAdam Skory mUri = null; 4116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) { 4216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn Uri uri = intent.getData(); 4316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn if (uri != null) { 4416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn if ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) { 45dfc23dd185d291c796f2939e4f8be0a8efc17ccbDianne Hackborn mUri = uri; 4616036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 4716036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 4816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 4916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 5016036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn 5116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn /** 5216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * Sets the Intent associated with the content, describing the current top-level context of 5316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * the activity. If this contains a reference to a piece of data related to the activity, 5416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * be sure to set {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} so the accessibility 5516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * service can access it. 5616036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn */ 5716036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn public void setIntent(Intent intent) { 5816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mIsAppProvidedIntent = true; 5916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mIntent = intent; 6069c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn } 6169c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn 6216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn /** 6316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * Returns the current {@link #setIntent} if one is set, else the default Intent obtained from 6416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * {@link android.app.Activity#getIntent Activity.getIntent}. Can be modified in-place. 6516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn */ 6669c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn public Intent getIntent() { 6716036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn return mIntent; 6816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 6916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn 7016036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn /** 7116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * Returns whether or not the current Intent was explicitly provided in 7216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}. If not, 7316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * the Intent was automatically set based on 7416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * {@link android.app.Activity#getIntent Activity.getIntent}. 7516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn */ 7616036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn public boolean isAppProvidedIntent() { 7716036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn return mIsAppProvidedIntent; 7816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 7916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn 8016036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn /** 8116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * Optional additional content items that are involved with 8216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * the current UI. Access to this content will be granted to the assistant as if you 8316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * are sending it through an Intent with {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}. 8416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn */ 8516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn public void setClipData(ClipData clip) { 8616036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mClipData = clip; 8716036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 8816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn 8916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn /** 9016036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * Return the current {@link #setClipData}, which you can modify in-place. 9116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn */ 9216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn public ClipData getClipData() { 9316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn return mClipData; 9416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 9516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn 9616036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn /** 9716036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * Sets optional structured data regarding the content being viewed. The provided data 9816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * must be a string represented with <a href="http://json-ld.org/">JSON-LD</a> using the 9916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * <a href="http://schema.org/">schema.org</a> vocabulary. 10016036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn */ 10116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn public void setStructuredData(String structuredData) { 10216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mStructuredData = structuredData; 10316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 10416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn 10516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn /** 10616036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * Returns the current {@link #setStructuredData}. 10716036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn */ 10816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn public String getStructuredData() { 10916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn return mStructuredData; 11016036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 11116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn 11216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn /** 11316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * Set a web URI associated with the current data being shown to the user. 11416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * This URI could be opened in a web browser, or in the app as an 11516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * {@link Intent#ACTION_VIEW} Intent, to show the same data that is currently 11616036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * being displayed by it. The URI here should be something that is transportable 11716036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * off the device into other environments to acesss the same data as is currently 11816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * being shown in the app; if the app does not have such a representation, it should 11916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * leave the null and only report the local intent and clip data. 12016036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn */ 12116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn public void setWebUri(Uri uri) { 122dfc23dd185d291c796f2939e4f8be0a8efc17ccbDianne Hackborn mIsAppProvidedWebUri = true; 12316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mUri = uri; 12416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 12516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn 12616036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn /** 12716036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * Return the content's web URI as per {@link #setWebUri(android.net.Uri)}, or null if 12816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * there is none. 12916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn */ 13016036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn public Uri getWebUri() { 13116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn return mUri; 13216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 13316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn 13416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn /** 135dfc23dd185d291c796f2939e4f8be0a8efc17ccbDianne Hackborn * Returns whether or not the current {@link #getWebUri} was explicitly provided in 136dfc23dd185d291c796f2939e4f8be0a8efc17ccbDianne Hackborn * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}. If not, 137dfc23dd185d291c796f2939e4f8be0a8efc17ccbDianne Hackborn * the Intent was automatically set based on 138dfc23dd185d291c796f2939e4f8be0a8efc17ccbDianne Hackborn * {@link android.app.Activity#getIntent Activity.getIntent}. 139dfc23dd185d291c796f2939e4f8be0a8efc17ccbDianne Hackborn */ 140dfc23dd185d291c796f2939e4f8be0a8efc17ccbDianne Hackborn public boolean isAppProvidedWebUri() { 141dfc23dd185d291c796f2939e4f8be0a8efc17ccbDianne Hackborn return mIsAppProvidedWebUri; 142dfc23dd185d291c796f2939e4f8be0a8efc17ccbDianne Hackborn } 143dfc23dd185d291c796f2939e4f8be0a8efc17ccbDianne Hackborn 144dfc23dd185d291c796f2939e4f8be0a8efc17ccbDianne Hackborn /** 14516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn * Return Bundle for extra vendor-specific data that can be modified and examined. 14616036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn */ 14716036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn public Bundle getExtras() { 14816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn return mExtras; 14916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 15016036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn 15116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn AssistContent(Parcel in) { 15216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn if (in.readInt() != 0) { 15316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mIntent = Intent.CREATOR.createFromParcel(in); 15416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 15516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn if (in.readInt() != 0) { 15616036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mClipData = ClipData.CREATOR.createFromParcel(in); 15716036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 15816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn if (in.readInt() != 0) { 15916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mUri = Uri.CREATOR.createFromParcel(in); 16016036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 16116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn if (in.readInt() != 0) { 16216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mStructuredData = in.readString(); 16316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 16416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mIsAppProvidedIntent = in.readInt() == 1; 16516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mExtras = in.readBundle(); 166a5381085d399bd7e78a5f8df4a3e5e74ee90676dAdam Skory mIsAppProvidedWebUri = in.readInt() == 1; 16716036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 16816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn 16916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn void writeToParcelInternal(Parcel dest, int flags) { 17016036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn if (mIntent != null) { 17116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn dest.writeInt(1); 17216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mIntent.writeToParcel(dest, flags); 17316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } else { 17416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn dest.writeInt(0); 17516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 17616036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn if (mClipData != null) { 17716036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn dest.writeInt(1); 17816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mClipData.writeToParcel(dest, flags); 17916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } else { 18016036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn dest.writeInt(0); 18116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 18216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn if (mUri != null) { 18316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn dest.writeInt(1); 18416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn mUri.writeToParcel(dest, flags); 18516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } else { 18616036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn dest.writeInt(0); 18716036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 18816036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn if (mStructuredData != null) { 18916036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn dest.writeInt(1); 19016036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn dest.writeString(mStructuredData); 19116036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } else { 19216036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn dest.writeInt(0); 19316036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn } 19416036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn dest.writeInt(mIsAppProvidedIntent ? 1 : 0); 19516036f26847f3f1a88a093fb776bf081008ff8d8Dianne Hackborn dest.writeBundle(mExtras); 196a5381085d399bd7e78a5f8df4a3e5e74ee90676dAdam Skory dest.writeInt(mIsAppProvidedWebUri ? 1 : 0); 19769c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn } 19869c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn 19969c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn @Override 20069c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn public int describeContents() { 20169c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn return 0; 20269c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn } 20369c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn 20469c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn @Override 20569c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn public void writeToParcel(Parcel dest, int flags) { 20669c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn writeToParcelInternal(dest, flags); 20769c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn } 20869c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn 20969c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn public static final Parcelable.Creator<AssistContent> CREATOR 21069c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn = new Parcelable.Creator<AssistContent>() { 21169c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn public AssistContent createFromParcel(Parcel in) { 21269c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn return new AssistContent(in); 21369c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn } 21469c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn 21569c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn public AssistContent[] newArray(int size) { 21669c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn return new AssistContent[size]; 21769c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn } 21869c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn }; 21969c6adc96eecfde74ceb83cf9177428dc08b6067Dianne Hackborn} 220