Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1186faa9 authored by Rakesh Iyer's avatar Rakesh Iyer
Browse files

System UI for auto.

This change adds in the beginnings of System UI for
the automotive use case. We extend the Phone status
and navigation bar and override the parts which are
customized for auto.

The navigation bar itself is built from a resource
array specified in car_arrays.xml to allow of ease
of customization of the shortcuts that are in the
navigation bar.

Bug: 26301185
Change-Id: I780a2ef9dd5ae2a4be9355b5874d08f521a86fa7
parent 982dcf3e
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
  public void setGlowScale(float);
}

-keep class com.android.systemui.statusbar.car.CarStatusBar
-keep class com.android.systemui.statusbar.phone.PhoneStatusBar
-keep class com.android.systemui.statusbar.tv.TvStatusBar

+51 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 2016, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->

<com.android.systemui.statusbar.car.CarNavigationBarView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:background="@drawable/system_bar_background">

    <!-- phone.NavigationBarView has rot0 and rot90 but we expect the car head unit to have a fixed
         rotation so skip this level of the heirarchy.
    -->
    <LinearLayout
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:orientation="horizontal"
        android:clipChildren="false"
        android:clipToPadding="false"
        android:id="@+id/nav_buttons"
        android:animateLayoutChanges="true">

        <!-- Buttons get populated here from a car_arrays.xml. -->
    </LinearLayout>

    <!-- lights out layout to match exactly -->
    <LinearLayout
        android:layout_height="match_parent"
        android:layout_width="match_parent"
        android:orientation="horizontal"
        android:id="@+id/lights_out"
        android:visibility="gone">
        <!-- Must match nav_buttons. -->
    </LinearLayout>

</com.android.systemui.statusbar.car.CarNavigationBarView>
+28 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 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.
*/
-->
<resources>
    <!-- These should be overriden in an overlay. The default implementation is empty.
         There needs to be correspondence per index between these arrays, which means that if there
         isn't a longpress action associated with a shortcut item, put in an empty item to make
         sure everything lines up.
    -->
    <array name="car_shortcut_icons" />
    <array name="car_shortcut_intent_uris" />
    <array name="car_shortcut_longpress_intent_uris" />
</resources>
+152 −0
Original line number Diff line number Diff line
/*
 * 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 com.android.systemui.statusbar.car;

import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.R.color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;

import com.android.systemui.R;
import com.android.systemui.statusbar.phone.ActivityStarter;
import com.android.systemui.statusbar.phone.NavigationBarView;
import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
import com.android.systemui.statusbar.policy.KeyButtonView;

import java.net.URISyntaxException;

/**
 * A custom navigation bar for the automotive use case.
 * <p>
 * The navigation bar in the automotive use case is more like a list of shortcuts, which we
 * expect to be customizable by the car OEMs. This implementation populates the nav_buttons layout
 * from resources rather than the layout file so customization would then mean updating
 * arrays_car.xml appropriately in an overlay.
 */
class CarNavigationBarView extends NavigationBarView {
    private ActivityStarter mActivityStarter;

    public CarNavigationBarView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void onFinishInflate() {
        // Read up arrays_car.xml and populate the navigation bar here.
        Context context = getContext();
        Resources r = getContext().getResources();
        TypedArray icons = r.obtainTypedArray(R.array.car_shortcut_icons);
        TypedArray intents = r.obtainTypedArray(R.array.car_shortcut_intent_uris);
        TypedArray longpressIntents =
                r.obtainTypedArray(R.array.car_shortcut_longpress_intent_uris);

        if (icons.length() != intents.length()) {
            throw new RuntimeException("car_shortcut_icons and car_shortcut_intents do not match");
        }

        LinearLayout navButtons = (LinearLayout) findViewById(R.id.nav_buttons);
        LinearLayout lightsOut = (LinearLayout) findViewById(R.id.lights_out);

        for (int i = 0; i < icons.length(); i++) {
            Drawable icon = icons.getDrawable(i);

            try {
                Intent intent = Intent.parseUri(intents.getString(i), Intent.URI_INTENT_SCHEME);
                Intent longpress = null;
                String longpressUri = longpressIntents.getString(i);
                if (!longpressUri.isEmpty()) {
                    longpress = Intent.parseUri(longpressUri, Intent.URI_INTENT_SCHEME);
                }

                // nav_buttons and lights_out should match exactly.
                navButtons.addView(makeButton(context, icon, intent, longpress));
                lightsOut.addView(makeButton(context, icon, intent, longpress));
            } catch (URISyntaxException e) {
                throw new RuntimeException("Malformed intent uri", e);
            }
        }
    }

    private ImageButton makeButton(Context context, Drawable icon,
            final Intent intent, final Intent longpress) {
        ImageButton button = new ImageButton(context);

        button.setImageDrawable(icon);
        button.setScaleType(ScaleType.CENTER);
        button.setBackgroundColor(color.transparent);
        LinearLayout.LayoutParams lp =
                new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1);
        button.setLayoutParams(lp);

        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mActivityStarter != null) {
                    mActivityStarter.startActivity(intent, true);
                }
            }
        });

        // Long click handlers are optional.
        if (longpress != null) {
            button.setLongClickable(true);
            button.setOnLongClickListener(new OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    if (mActivityStarter != null) {
                        mActivityStarter.startActivity(longpress, true);
                        return true;
                    }
                    return false;
                }
            });
        } else {
            button.setLongClickable(false);
        }

        return button;
    }

    public void setActivityStarter(ActivityStarter activityStarter) {
        mActivityStarter = activityStarter;
    }

    @Override
    public void setDisabledFlags(int disabledFlags, boolean force) {
        // TODO: Populate.
    }

    @Override
    public void reorient() {
        // We expect the car head unit to always have a fixed rotation so we ignore this. The super
        // class implentation expects mRotatedViews to be populated, so if you call into it, there
        // is a possibility of a NullPointerException.
    }

    @Override
    public View getCurrentView() {
        return this;
    }
}
+60 −0
Original line number Diff line number Diff line
/*
 * 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 com.android.systemui.statusbar.car;

import android.content.Context;
import android.graphics.PixelFormat;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.WindowManager;

import com.android.systemui.R;
import com.android.systemui.statusbar.phone.PhoneStatusBar;

/**
 * A status bar (and navigation bar) tailored for the automotive use case.
 */
public class CarStatusBar extends PhoneStatusBar {
    @Override
    protected void addNavigationBar() {
        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
                    WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
                    | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
                PixelFormat.TRANSLUCENT);
        lp.setTitle("CarNavigationBar");
        lp.windowAnimations = 0;
        mWindowManager.addView(mNavigationBarView, lp);
    }

    @Override
    protected void createNavigationBarView(Context context) {
        if (mNavigationBarView != null) {
            return;
        }

        CarNavigationBarView carNavBar =
                (CarNavigationBarView) View.inflate(context, R.layout.car_navigation_bar, null);
        carNavBar.setActivityStarter(this);
        mNavigationBarView = carNavBar;
    }
}
Loading