1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.car;
17
18import android.app.Notification;
19import android.app.NotificationChannel;
20import android.app.NotificationManager;
21import android.content.Context;
22import android.os.Build;
23import android.util.Log;
24
25import com.android.internal.annotations.GuardedBy;
26
27import java.util.HashSet;
28import java.util.Set;
29
30/**
31 * Class used to notify user about CAN bus failure.
32 */
33final class CanBusErrorNotifier {
34    private static final String TAG = CarLog.TAG_CAN_BUS + ".NOTIFIER";
35    private static final int NOTIFICATION_ID = 1;
36    private static final boolean IS_RELEASE_BUILD = "user".equals(Build.TYPE);
37
38    private final Context mContext;
39    private final NotificationManager mNotificationManager;
40
41    // Contains a set of objects that reported failure. The notification will be hidden only when
42    // this set is empty (all reported objects are in love and peace with the vehicle).
43    @GuardedBy("this")
44    private final Set<Object> mReportedObjects = new HashSet<>();
45
46    CanBusErrorNotifier(Context context) {
47        mNotificationManager = (NotificationManager) context.getSystemService(
48                Context.NOTIFICATION_SERVICE);
49        mContext = context;
50    }
51
52    public void removeFailureReport(Object sender) {
53        setCanBusFailure(false, sender);
54    }
55
56    public void reportFailure(Object sender) {
57        setCanBusFailure(true, sender);
58    }
59
60    private void setCanBusFailure(boolean failed, Object sender) {
61        boolean shouldShowNotification;
62        synchronized (this) {
63            boolean changed = failed
64                    ? mReportedObjects.add(sender) : mReportedObjects.remove(sender);
65
66            if (!changed) {
67                return;
68            }
69
70            shouldShowNotification = !mReportedObjects.isEmpty();
71        }
72
73        if (Log.isLoggable(TAG, Log.INFO)) {
74            Log.i(TAG, "Changing CAN bus failure state to " + shouldShowNotification);
75        }
76
77        if (shouldShowNotification) {
78            showNotification();
79        } else {
80            hideNotification();
81        }
82    }
83
84    private void showNotification() {
85        if (IS_RELEASE_BUILD) {
86            // TODO: for user, we should show message to take car to the dealer. bug:32096297
87            return;
88        }
89        Notification notification =
90                new Notification.Builder(mContext, NotificationChannel.DEFAULT_CHANNEL_ID)
91                        .setContentTitle(mContext.getString(R.string.car_can_bus_failure))
92                        .setContentText(mContext.getString(R.string.car_can_bus_failure_desc))
93                        .setSmallIcon(R.drawable.car_ic_error)
94                        .setOngoing(true)
95                        .build();
96        mNotificationManager.notify(TAG, NOTIFICATION_ID, notification);
97    }
98
99    private void hideNotification() {
100        if (IS_RELEASE_BUILD) {
101            // TODO: for user, we should show message to take car to the dealer. bug:32096297
102            return;
103        }
104        mNotificationManager.cancel(TAG, NOTIFICATION_ID);
105    }
106}
107