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 
17 package com.android.systemui.statusbar.policy;
18 
19 import android.app.ActivityManager;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.os.UserHandle;
25 import android.text.format.DateFormat;
26 import android.util.AttributeSet;
27 import android.widget.LinearLayout;
28 import android.widget.TextClock;
29 
30 import 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  */
36 public 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 
SplitClockView(Context context, AttributeSet attrs)55     public SplitClockView(Context context, AttributeSet attrs) {
56         super(context, attrs);
57     }
58 
59     @Override
onFinishInflate()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
onAttachedToWindow()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
onDetachedFromWindow()84     protected void onDetachedFromWindow() {
85         super.onDetachedFromWindow();
86         getContext().unregisterReceiver(mIntentReceiver);
87     }
88 
updatePatterns()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         mTimeView.setContentDescriptionFormat12Hour(formatString);
105         mTimeView.setContentDescriptionFormat24Hour(formatString);
106         mAmPmView.setFormat12Hour(amPmString);
107         mAmPmView.setFormat24Hour(amPmString);
108     }
109 
110     /**
111      * @return the index where the AM/PM part starts at the end in {@code formatString} including
112      *         leading white spaces or {@code -1} if no AM/PM part is found or {@code formatString}
113      *         doesn't end with AM/PM part
114      */
getAmPmPartEndIndex(String formatString)115     private static int getAmPmPartEndIndex(String formatString) {
116         boolean hasAmPm = false;
117         int length = formatString.length();
118         for (int i = length - 1; i >= 0; i--) {
119             char c = formatString.charAt(i);
120             boolean isAmPm = c == 'a';
121             boolean isWhitespace = Character.isWhitespace(c);
122             if (isAmPm) {
123                 hasAmPm = true;
124             }
125             if (isAmPm || isWhitespace) {
126                 continue;
127             }
128             if (i == length - 1) {
129 
130                 // First character was not AM/PM and not whitespace, so it's not ending with AM/PM.
131                 return -1;
132             } else {
133 
134                 // If we have AM/PM at all, return last index, or -1 to indicate that it's not
135                 // ending with AM/PM.
136                 return hasAmPm ? i + 1 : -1;
137             }
138         }
139 
140         // Only AM/PM and whitespaces? The whole string is AM/PM. Else: Only whitespaces in the
141         // string.
142         return hasAmPm ? 0 : -1;
143     }
144 
145 }
146