1/*
2 * Copyright (C) 2014 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 */
16
17package com.android.systemui.statusbar.policy;
18
19import android.app.ActivityManager;
20import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.os.UserHandle;
25import android.text.format.DateFormat;
26import android.util.AttributeSet;
27import android.widget.LinearLayout;
28import android.widget.TextClock;
29
30import com.android.systemui.R;
31
32/**
33 * Container for a clock which has two separate views for the clock itself and AM/PM indicator. This
34 * is used to scale the clock independently of AM/PM.
35 */
36public class SplitClockView extends LinearLayout {
37
38    private TextClock mTimeView;
39    private TextClock mAmPmView;
40
41    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
42        @Override
43        public void onReceive(Context context, Intent intent) {
44            final String action = intent.getAction();
45            if (Intent.ACTION_TIME_CHANGED.equals(action)
46                    || Intent.ACTION_TIMEZONE_CHANGED.equals(action)
47                    || Intent.ACTION_LOCALE_CHANGED.equals(action)
48                    || Intent.ACTION_CONFIGURATION_CHANGED.equals(action)
49                    || Intent.ACTION_USER_SWITCHED.equals(action)) {
50                updatePatterns();
51            }
52        }
53    };
54
55    public SplitClockView(Context context, AttributeSet attrs) {
56        super(context, attrs);
57    }
58
59    @Override
60    protected void onFinishInflate() {
61        super.onFinishInflate();
62        mTimeView = (TextClock) findViewById(R.id.time_view);
63        mAmPmView = (TextClock) findViewById(R.id.am_pm_view);
64        mTimeView.setShowCurrentUserTime(true);
65        mAmPmView.setShowCurrentUserTime(true);
66    }
67
68    @Override
69    protected void onAttachedToWindow() {
70        super.onAttachedToWindow();
71
72        IntentFilter filter = new IntentFilter();
73        filter.addAction(Intent.ACTION_TIME_CHANGED);
74        filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
75        filter.addAction(Intent.ACTION_LOCALE_CHANGED);
76        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
77        filter.addAction(Intent.ACTION_USER_SWITCHED);
78        getContext().registerReceiverAsUser(mIntentReceiver, UserHandle.ALL, filter, null, null);
79
80        updatePatterns();
81    }
82
83    @Override
84    protected void onDetachedFromWindow() {
85        super.onDetachedFromWindow();
86        getContext().unregisterReceiver(mIntentReceiver);
87    }
88
89    private void updatePatterns() {
90        String formatString = DateFormat.getTimeFormatString(getContext(),
91                ActivityManager.getCurrentUser());
92        int index = getAmPmPartEndIndex(formatString);
93        String timeString;
94        String amPmString;
95        if (index == -1) {
96            timeString = formatString;
97            amPmString = "";
98        } else {
99            timeString = formatString.substring(0, index);
100            amPmString = formatString.substring(index);
101        }
102        mTimeView.setFormat12Hour(timeString);
103        mTimeView.setFormat24Hour(timeString);
104        mAmPmView.setFormat12Hour(amPmString);
105        mAmPmView.setFormat24Hour(amPmString);
106    }
107
108    /**
109     * @return the index where the AM/PM part starts at the end in {@code formatString} including
110     *         leading white spaces or {@code -1} if no AM/PM part is found or {@code formatString}
111     *         doesn't end with AM/PM part
112     */
113    private static int getAmPmPartEndIndex(String formatString) {
114        boolean hasAmPm = false;
115        int length = formatString.length();
116        for (int i = length - 1; i >= 0; i--) {
117            char c = formatString.charAt(i);
118            boolean isAmPm = c == 'a';
119            boolean isWhitespace = Character.isWhitespace(c);
120            if (isAmPm) {
121                hasAmPm = true;
122            }
123            if (isAmPm || isWhitespace) {
124                continue;
125            }
126            if (i == length - 1) {
127
128                // First character was not AM/PM and not whitespace, so it's not ending with AM/PM.
129                return -1;
130            } else {
131
132                // If we have AM/PM at all, return last index, or -1 to indicate that it's not
133                // ending with AM/PM.
134                return hasAmPm ? i + 1 : -1;
135            }
136        }
137
138        // Only AM/PM and whitespaces? The whole string is AM/PM. Else: Only whitespaces in the
139        // string.
140        return hasAmPm ? 0 : -1;
141    }
142
143}
144