android.support.car.ui.CarNavExtender.java Source code

Java tutorial

Introduction

Here is the source code for android.support.car.ui.CarNavExtender.java

Source

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package android.support.car.ui;

import android.app.Notification;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.annotation.DrawableRes;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Helper class to add navigation extensions to notifications for use in Android Auto.
 * <p>
 * To create a notification with navigation extensions:
 * <ol>
 *   <li>Create a {@link android.app.Notification.Builder}, setting any desired
 *   properties.
 *   <li>Create a {@link CarNavExtender}.
 *   <li>Set car-specific properties using the
 *   {@code add} and {@code set} methods of {@link CarNavExtender}.
 *   <li>Call {@link android.app.Notification.Builder#extend} to apply the extensions to a
 *   notification.
 *   <li>Post the notification to the notification system with the
 *   {@code NotificationManager.notify(...)} methods.
 * </ol>
 *
 * <pre class="prettyprint">
 * Notification notif = new Notification.Builder(mContext)
 *         .setContentTitle("Turn right in 2.0 miles on to US 101-N")
 *         .setContentText("43 mins (32 mi) to Home")
 *         .setSmallIcon(R.drawable.ic_nav)
 *         .extend(new CarNavExtender()
 *                 .setContentTitle("US 101-N")
 *                 .setContentText("400 ft")
 *                 .setSubText("43 mins to Home")
 *         .build();
 * NotificationManager notificationManger =
 *         (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
 * notificationManger.notify(0, notif);</pre>
 *
 * <p>CarNavExtender fields can be accessed on an existing notification by using the
 * {@code CarNavExtender(Notification)} constructor,
 * and then using the {@code get} methods to access values.
 */
public class CarNavExtender implements NotificationCompat.Extender {
    /** This value must remain unchanged for compatibility. **/
    private static final String EXTRA_CAR_EXTENDER = "android.car.EXTENSIONS";
    private static final String EXTRA_IS_EXTENDED = "com.google.android.gms.car.support.CarNavExtender.EXTENDED";
    private static final String EXTRA_CONTENT_ID = "content_id";
    private static final String EXTRA_TYPE = "type";
    private static final String EXTRA_SUB_TEXT = "sub_text";
    private static final String EXTRA_ACTION_ICON = "action_icon";
    /** This value must remain unchanged for compatibility. **/
    private static final String EXTRA_CONTENT_INTENT = "content_intent";
    /** This value must remain unchanged for compatibility. **/
    private static final String EXTRA_COLOR = "app_color";
    private static final String EXTRA_NIGHT_COLOR = "app_night_color";
    /** This value must remain unchanged for compatibility. **/
    private static final String EXTRA_STREAM_VISIBILITY = "stream_visibility";
    /** This value must remain unchanged for compatibility. **/
    private static final String EXTRA_HEADS_UP_VISIBILITY = "heads_up_visibility";
    private static final String EXTRA_IGNORE_IN_STREAM = "ignore_in_stream";

    @IntDef({ TYPE_HERO, TYPE_NORMAL })
    @Retention(RetentionPolicy.SOURCE)
    private @interface Type {
    }

    public static final int TYPE_HERO = 0;
    public static final int TYPE_NORMAL = 1;

    private boolean mIsExtended;
    /** <code>null</code> if not explicitly set. **/
    private Long mContentId;
    private int mType = TYPE_NORMAL;
    private CharSequence mContentTitle;
    private CharSequence mContentText;
    private CharSequence mSubText;
    private Bitmap mLargeIcon;
    private @DrawableRes int mActionIcon;
    private Intent mContentIntent;
    private int mColor = Notification.COLOR_DEFAULT;
    private int mNightColor = Notification.COLOR_DEFAULT;
    private boolean mShowInStream = true;
    private boolean mShowAsHeadsUp;
    private boolean mIgnoreInStream;

    /**
     * Create a new CarNavExtender to extend a new notification.
     */
    public CarNavExtender() {
    }

    /**
     * Reconstruct a CarNavExtender from an existing notification. Can be used to retrieve values.
     *
     * @param notification The notification to retrieve the values from.
     */
    public CarNavExtender(@NonNull Notification notification) {
        Bundle extras = NotificationCompat.getExtras(notification);
        if (extras == null) {
            return;
        }
        Bundle b = extras.getBundle(EXTRA_CAR_EXTENDER);
        if (b == null) {
            return;
        }

        mIsExtended = b.getBoolean(EXTRA_IS_EXTENDED);
        mContentId = (Long) b.getSerializable(EXTRA_CONTENT_ID);
        // The ternary guarantees that we return either TYPE_HERO or TYPE_NORMAL.
        mType = (b.getInt(EXTRA_TYPE, TYPE_NORMAL) == TYPE_HERO) ? TYPE_HERO : TYPE_NORMAL;
        mContentTitle = b.getCharSequence(Notification.EXTRA_TITLE);
        mContentText = b.getCharSequence(Notification.EXTRA_TEXT);
        mSubText = b.getCharSequence(EXTRA_SUB_TEXT);
        mLargeIcon = b.getParcelable(Notification.EXTRA_LARGE_ICON);
        mActionIcon = b.getInt(EXTRA_ACTION_ICON);
        mContentIntent = b.getParcelable(EXTRA_CONTENT_INTENT);
        mColor = b.getInt(EXTRA_COLOR, Notification.COLOR_DEFAULT);
        mNightColor = b.getInt(EXTRA_NIGHT_COLOR, Notification.COLOR_DEFAULT);
        mShowInStream = b.getBoolean(EXTRA_STREAM_VISIBILITY, true);
        mShowAsHeadsUp = b.getBoolean(EXTRA_HEADS_UP_VISIBILITY);
        mIgnoreInStream = b.getBoolean(EXTRA_IGNORE_IN_STREAM);
    }

    @Override
    public NotificationCompat.Builder extend(NotificationCompat.Builder builder) {
        Bundle b = new Bundle();
        b.putBoolean(EXTRA_IS_EXTENDED, true);
        b.putSerializable(EXTRA_CONTENT_ID, mContentId);
        b.putInt(EXTRA_TYPE, mType);
        b.putCharSequence(Notification.EXTRA_TITLE, mContentTitle);
        b.putCharSequence(Notification.EXTRA_TEXT, mContentText);
        b.putCharSequence(EXTRA_SUB_TEXT, mSubText);
        b.putParcelable(Notification.EXTRA_LARGE_ICON, mLargeIcon);
        b.putInt(EXTRA_ACTION_ICON, mActionIcon);
        b.putParcelable(EXTRA_CONTENT_INTENT, mContentIntent);
        b.putInt(EXTRA_COLOR, mColor);
        b.putInt(EXTRA_NIGHT_COLOR, mNightColor);
        b.putBoolean(EXTRA_STREAM_VISIBILITY, mShowInStream);
        b.putBoolean(EXTRA_HEADS_UP_VISIBILITY, mShowAsHeadsUp);
        b.putBoolean(EXTRA_IGNORE_IN_STREAM, mIgnoreInStream);
        builder.getExtras().putBundle(EXTRA_CAR_EXTENDER, b);
        return builder;
    }

    /**
     * @return <code>true</code> if the notification was extended with {@link CarNavExtender}.
     */
    public boolean isExtended() {
        return mIsExtended;
    }

    /**
     * Static version of {@link #isExtended()}.
     */
    public static boolean isExtended(Notification notification) {
        Bundle extras = NotificationCompat.getExtras(notification);
        if (extras == null) {
            return false;
        }

        extras = extras.getBundle(EXTRA_CAR_EXTENDER);
        return extras != null && extras.getBoolean(EXTRA_IS_EXTENDED);
    }

    /**
     * Sets an id for the content of this notification. If the content id matches an existing
     * notification, any timers that control ranking and heads up notification will remain
     * unchanged. However, if it differs from the previous notification with the same id then
     * this notification will be treated as a new notification with respect to heads up
     * notifications and ranking.
     *
     * If no content id is specified, it will be treated like a new content id.
     *
     * A content id will only be compared to the existing notification, not the entire history of
     * content ids.
     *
     * @param contentId The content id that represents this notification.
     * @return This object for method chaining.
     */
    public CarNavExtender setContentId(long contentId) {
        mContentId = contentId;
        return this;
    }

    /**
     * @return The content id for this notification or <code>null</code> if it was not specified.
     */
    @Nullable
    public Long getContentId() {
        return mContentId;
    }

    /**
     * @param type The type of notification that this will be displayed as in the Android Auto.
     * @return This object for method chaining.
     *
     * @see #TYPE_NORMAL
     * @see #TYPE_HERO
     */
    public CarNavExtender setType(@Type int type) {
        mType = type;
        return this;
    }

    /**
     * @return The type of notification
     *
     * @see #TYPE_NORMAL
     * @see #TYPE_HERO
     */
    @Type
    public int getType() {
        return mType;
    }

    /**
     * @return The type without having to construct an entire {@link CarNavExtender} object.
     */
    @Type
    public static int getType(Notification notification) {
        Bundle extras = NotificationCompat.getExtras(notification);
        if (extras == null) {
            return TYPE_NORMAL;
        }
        Bundle b = extras.getBundle(EXTRA_CAR_EXTENDER);
        if (b == null) {
            return TYPE_NORMAL;
        }

        // The ternary guarantees that we return either TYPE_HERO or TYPE_NORMAL.
        return (b.getInt(EXTRA_TYPE, TYPE_NORMAL) == TYPE_HERO) ? TYPE_HERO : TYPE_NORMAL;
    }

    /**
     * @param contentTitle Override for the notification's content title.
     * @return This object for method chaining.
     */
    public CarNavExtender setContentTitle(CharSequence contentTitle) {
        mContentTitle = contentTitle;
        return this;
    }

    /**
     * @return The content title for the notification if one was explicitly set with
     *         {@link #setContentTitle(CharSequence)}.
     */
    public CharSequence getContentTitle() {
        return mContentTitle;
    }

    /**
     * @param contentText Override for the notification's content text. If set to an empty string,
     *                    it will be treated as if there is no context text by the UI.
     * @return This object for method chaining.
     */
    public CarNavExtender setContentText(CharSequence contentText) {
        mContentText = contentText;
        return this;
    }

    /**
     * @return The content text for the notification if one was explicitly set with
     *         {@link #setContentText(CharSequence)}.
     */
    @Nullable
    public CharSequence getContentText() {
        return mContentText;
    }

    /**
     * @param subText A third text field that will be displayed on hero cards.
     * @return This object for method chaining.
     */
    public CarNavExtender setSubText(CharSequence subText) {
        mSubText = subText;
        return this;
    }

    /**
     * @return The secondary content text for the notification or null if it wasn't set.
     */
    @Nullable
    public CharSequence getSubText() {
        return mSubText;
    }

    /**
     * @param largeIcon Override for the notification's large icon.
     * @return This object for method chaining.
     */
    public CarNavExtender setLargeIcon(Bitmap largeIcon) {
        mLargeIcon = largeIcon;
        return this;
    }

    /**
     * @return The large icon for the notification if one was explicitly set with
     *         {@link #setLargeIcon(android.graphics.Bitmap)}.
     */
    public Bitmap getLargeIcon() {
        return mLargeIcon;
    }

    /**
     * By default, Android Auto will show a navigation chevron on cards. However, a separate icon
     * can be set here to override it.
     *
     * @param actionIcon The action icon resource id from your package that you would like to
     *                   use instead of the navigation chevron.
     * @return This object for method chaining.
     */
    public CarNavExtender setActionIcon(@DrawableRes int actionIcon) {
        mActionIcon = actionIcon;
        return this;
    }

    /**
     * @return The overridden action icon or 0 if one wasn't set.
     */
    @DrawableRes
    public int getActionIcon() {
        return mActionIcon;
    }

    /**
     * @param contentIntent The content intent that will be sent using
     *                      {@link com.google.android.gms.car.CarActivity#startCarProjectionActivity(android.content.Intent)}
     *                      It is STRONGLY suggested that you set a content intent or else the
     *                      notification will have no action when tapped.
     * @return This object for method chaining.
     */
    public CarNavExtender setContentIntent(Intent contentIntent) {
        mContentIntent = contentIntent;
        return this;
    }

    /**
     * @return The content intent that will be sent using
     *         {@link com.google.android.gms.car.CarActivity#startCarProjectionActivity(android.content.Intent)}
     */
    public Intent getContentIntent() {
        return mContentIntent;
    }

    /**
     * @param color Override for the notification color.
     * @return This object for method chaining.
     *
     * @see android.app.Notification.Builder#setColor(int)
     */
    public CarNavExtender setColor(int color) {
        mColor = color;
        return this;
    }

    /**
     * @return The color specified by the notification or {@link android.app.Notification#COLOR_DEFAULT} if
     *         one wasn't explicitly set with {@link #setColor(int)}.
     */
    public int getColor() {
        return mColor;
    }

    /**
     * @param nightColor Override for the notification color at night.
     * @return This object for method chaining.
     *
     * @see android.app.Notification.Builder#setColor(int)
     */
    public CarNavExtender setNightColor(int nightColor) {
        mNightColor = nightColor;
        return this;
    }

    /**
     * @return The night color specified by the notification or {@link android.app.Notification#COLOR_DEFAULT}
     *         if one wasn't explicitly set with {@link #setNightColor(int)}.
     */
    public int getNightColor() {
        return mNightColor;
    }

    /**
     * @param show Whether or not to show the notification in the stream.
     * @return This object for method chaining.
     */
    public CarNavExtender setShowInStream(boolean show) {
        mShowInStream = show;
        return this;
    }

    /**
     * @return Whether or not to show the notification in the stream.
     */
    public boolean getShowInStream() {
        return mShowInStream;
    }

    /**
     * @param show Whether or not to show the notification as a heads up notification.
     * @return This object for method chaining.
     */
    public CarNavExtender setShowAsHeadsUp(boolean show) {
        mShowAsHeadsUp = show;
        return this;
    }

    /**
     * @return Whether or not to show the notification as a heads up notification.
     */
    public boolean getShowAsHeadsUp() {
        return mShowAsHeadsUp;
    }

    /**
     * @param ignore Whether or not this notification can be shown as a heads-up notification if
     *               the user is already on the stream.
     * @return This object for method chaining.
     */
    public CarNavExtender setIgnoreInStream(boolean ignore) {
        mIgnoreInStream = ignore;
        return this;
    }

    /**
     * @return Whether or not the stream item can be shown as a heads-up notification if ther user
     *         already is on the stream.
     */
    public boolean getIgnoreInStream() {
        return mIgnoreInStream;
    }
}