SignalClusterView.java revision 5172dc2f36f9c417befd0957ce2ae20f9d083a88
12e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson/* 22e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson * Copyright (C) 2011 The Android Open Source Project 32e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson * 42e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson * Licensed under the Apache License, Version 2.0 (the "License"); 52e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson * you may not use this file except in compliance with the License. 62e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson * You may obtain a copy of the License at 72e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson * 82e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson * http://www.apache.org/licenses/LICENSE-2.0 92e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson * 102e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson * Unless required by applicable law or agreed to in writing, software 112e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson * distributed under the License is distributed on an "AS IS" BASIS, 122e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson * See the License for the specific language governing permissions and 142e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson * limitations under the License. 152e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson */ 162e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 172e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertsonpackage com.android.systemui.statusbar; 182e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 192e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertsonimport android.content.Context; 202e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertsonimport android.util.AttributeSet; 21cd686b5b6d4166b510df8e32138479a9559bc117John Spurlockimport android.util.Log; 222e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertsonimport android.view.View; 232e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertsonimport android.view.ViewGroup; 242f7dfa7afdaada78c46bd6fd7e307656ba3dd66aJohn Spurlockimport android.view.accessibility.AccessibilityEvent; 252e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertsonimport android.widget.ImageView; 262e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertsonimport android.widget.LinearLayout; 272e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 282e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertsonimport com.android.systemui.R; 29af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlockimport com.android.systemui.statusbar.policy.NetworkControllerImpl; 302e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 315ccff81a642844138b144ad2cc339eba188812a0Daniel Sandler// Intimately tied to the design of res/layout/signal_cluster_view.xml 322e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertsonpublic class SignalClusterView 332f7dfa7afdaada78c46bd6fd7e307656ba3dd66aJohn Spurlock extends LinearLayout 34af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock implements NetworkControllerImpl.SignalCluster { 352e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 3628f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler static final String TAG = "SignalClusterView"; 37b3eb89190c4bb4ebbe676328cd37830d50e6ed3eJohn Spurlock static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); 382f7dfa7afdaada78c46bd6fd7e307656ba3dd66aJohn Spurlock 39af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock NetworkControllerImpl mNC; 402e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 4128f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler private boolean mWifiVisible = false; 42fcc901c10bffdfb9c6b31e676dec36b47d949979John Spurlock private int mWifiStrengthId = 0; 4328f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler private boolean mMobileVisible = false; 44fcc901c10bffdfb9c6b31e676dec36b47d949979John Spurlock private int mMobileStrengthId = 0, mMobileTypeId = 0; 455ccff81a642844138b144ad2cc339eba188812a0Daniel Sandler private boolean mIsAirplaneMode = false; 46061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn private int mAirplaneIconId = 0; 47bcf6ef0b82c1daea43e03b8ad5af319ed324242aDaniel Sandler private String mWifiDescription, mMobileDescription, mMobileTypeDescription; 4814339c9edc2675d4757d572006625c2641db5653John Spurlock private boolean mRoaming; 4928f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler 502e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson ViewGroup mWifiGroup, mMobileGroup; 51fcc901c10bffdfb9c6b31e676dec36b47d949979John Spurlock ImageView mWifi, mMobile, mMobileType, mAirplane; 525172dc2f36f9c417befd0957ce2ae20f9d083a88Jorim Jaggi View mWifiAirplaneSpacer; 532e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 542e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson public SignalClusterView(Context context) { 552e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson this(context, null); 562e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson } 572e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 582e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson public SignalClusterView(Context context, AttributeSet attrs) { 592e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson this(context, attrs, 0); 602e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson } 612e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 622e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson public SignalClusterView(Context context, AttributeSet attrs, int defStyle) { 632e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson super(context, attrs, defStyle); 642e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson } 652e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 66af8d6c44f06d2f8baac2c5774a9efdae3fc36797John Spurlock public void setNetworkController(NetworkControllerImpl nc) { 67cd686b5b6d4166b510df8e32138479a9559bc117John Spurlock if (DEBUG) Log.d(TAG, "NetworkController=" + nc); 682e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson mNC = nc; 692e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson } 702e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 712e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson @Override 722e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson protected void onAttachedToWindow() { 732e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson super.onAttachedToWindow(); 742e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 752e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson mWifiGroup = (ViewGroup) findViewById(R.id.wifi_combo); 762e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson mWifi = (ImageView) findViewById(R.id.wifi_signal); 772e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson mMobileGroup = (ViewGroup) findViewById(R.id.mobile_combo); 782e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson mMobile = (ImageView) findViewById(R.id.mobile_signal); 792e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson mMobileType = (ImageView) findViewById(R.id.mobile_type); 80061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn mAirplane = (ImageView) findViewById(R.id.airplane); 815172dc2f36f9c417befd0957ce2ae20f9d083a88Jorim Jaggi mWifiAirplaneSpacer = findViewById(R.id.wifi_airplane_spacer); 8228f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler 8328f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler apply(); 842e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson } 852e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 862e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson @Override 872e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson protected void onDetachedFromWindow() { 8828f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler mWifiGroup = null; 8928f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler mWifi = null; 9028f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler mMobileGroup = null; 9128f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler mMobile = null; 9228f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler mMobileType = null; 93061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn mAirplane = null; 9428f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler 952e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson super.onDetachedFromWindow(); 962e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson } 972e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 98061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn @Override 99b3eb89190c4bb4ebbe676328cd37830d50e6ed3eJohn Spurlock public void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription) { 10028f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler mWifiVisible = visible; 10128f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler mWifiStrengthId = strengthIcon; 102bcf6ef0b82c1daea43e03b8ad5af319ed324242aDaniel Sandler mWifiDescription = contentDescription; 10328f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler 10428f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler apply(); 10528f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler } 10628f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler 107061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn @Override 108b3eb89190c4bb4ebbe676328cd37830d50e6ed3eJohn Spurlock public void setMobileDataIndicators(boolean visible, int strengthIcon, int typeIcon, 10914339c9edc2675d4757d572006625c2641db5653John Spurlock String contentDescription, String typeContentDescription, boolean roaming) { 11028f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler mMobileVisible = visible; 11128f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler mMobileStrengthId = strengthIcon; 11228f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler mMobileTypeId = typeIcon; 113bcf6ef0b82c1daea43e03b8ad5af319ed324242aDaniel Sandler mMobileDescription = contentDescription; 114bcf6ef0b82c1daea43e03b8ad5af319ed324242aDaniel Sandler mMobileTypeDescription = typeContentDescription; 11514339c9edc2675d4757d572006625c2641db5653John Spurlock mRoaming = roaming; 11628f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler 11728f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler apply(); 11828f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler } 11928f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler 120061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn @Override 121061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn public void setIsAirplaneMode(boolean is, int airplaneIconId) { 1225ccff81a642844138b144ad2cc339eba188812a0Daniel Sandler mIsAirplaneMode = is; 123061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn mAirplaneIconId = airplaneIconId; 124061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn 125061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn apply(); 1265ccff81a642844138b144ad2cc339eba188812a0Daniel Sandler } 1275ccff81a642844138b144ad2cc339eba188812a0Daniel Sandler 1282f7dfa7afdaada78c46bd6fd7e307656ba3dd66aJohn Spurlock @Override 1292f7dfa7afdaada78c46bd6fd7e307656ba3dd66aJohn Spurlock public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 1302f7dfa7afdaada78c46bd6fd7e307656ba3dd66aJohn Spurlock // Standard group layout onPopulateAccessibilityEvent() implementations 1312f7dfa7afdaada78c46bd6fd7e307656ba3dd66aJohn Spurlock // ignore content description, so populate manually 13224e028e0ec533cb7304296118a73bdc03870d10dDaniel Sandler if (mWifiVisible && mWifiGroup != null && mWifiGroup.getContentDescription() != null) 1332f7dfa7afdaada78c46bd6fd7e307656ba3dd66aJohn Spurlock event.getText().add(mWifiGroup.getContentDescription()); 13424e028e0ec533cb7304296118a73bdc03870d10dDaniel Sandler if (mMobileVisible && mMobileGroup != null && mMobileGroup.getContentDescription() != null) 1352f7dfa7afdaada78c46bd6fd7e307656ba3dd66aJohn Spurlock event.getText().add(mMobileGroup.getContentDescription()); 1362f7dfa7afdaada78c46bd6fd7e307656ba3dd66aJohn Spurlock return super.dispatchPopulateAccessibilityEvent(event); 1372f7dfa7afdaada78c46bd6fd7e307656ba3dd66aJohn Spurlock } 1382f7dfa7afdaada78c46bd6fd7e307656ba3dd66aJohn Spurlock 1394662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio @Override 1404662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio public void onRtlPropertiesChanged(int layoutDirection) { 1414662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio super.onRtlPropertiesChanged(layoutDirection); 1424662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio 1434662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio if (mWifi != null) { 1444662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio mWifi.setImageDrawable(null); 1454662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio } 1464662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio 1474662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio if (mMobile != null) { 1484662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio mMobile.setImageDrawable(null); 1494662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio } 150fcc901c10bffdfb9c6b31e676dec36b47d949979John Spurlock 1514662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio if (mMobileType != null) { 1524662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio mMobileType.setImageDrawable(null); 1534662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio } 1544662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio 1554662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio if(mAirplane != null) { 1564662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio mAirplane.setImageDrawable(null); 1574662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio } 1584662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio 1594662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio apply(); 1604662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio } 1614662611f3757bd9210f252c095f2bef278fa2043Fabrice Di Meglio 1620d266899da8f612194a8393ec69c4fd870f2f45cJorim Jaggi @Override 1630d266899da8f612194a8393ec69c4fd870f2f45cJorim Jaggi public boolean hasOverlappingRendering() { 1640d266899da8f612194a8393ec69c4fd870f2f45cJorim Jaggi return false; 1650d266899da8f612194a8393ec69c4fd870f2f45cJorim Jaggi } 1660d266899da8f612194a8393ec69c4fd870f2f45cJorim Jaggi 16728f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler // Run after each indicator change. 16828f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler private void apply() { 1692e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson if (mWifiGroup == null) return; 1702e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 17128f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler if (mWifiVisible) { 17228f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler mWifi.setImageResource(mWifiStrengthId); 173bcf6ef0b82c1daea43e03b8ad5af319ed324242aDaniel Sandler mWifiGroup.setContentDescription(mWifiDescription); 174cda096ebf3fac67daf36e775547c2a337374927bFabrice Di Meglio mWifiGroup.setVisibility(View.VISIBLE); 1752e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson } else { 1762e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson mWifiGroup.setVisibility(View.GONE); 1772e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson } 1782e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 179cd686b5b6d4166b510df8e32138479a9559bc117John Spurlock if (DEBUG) Log.d(TAG, 180fcc901c10bffdfb9c6b31e676dec36b47d949979John Spurlock String.format("wifi: %s sig=%d", 18128f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler (mWifiVisible ? "VISIBLE" : "GONE"), 182fcc901c10bffdfb9c6b31e676dec36b47d949979John Spurlock mWifiStrengthId)); 1832e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 184061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn if (mMobileVisible && !mIsAirplaneMode) { 18528f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler mMobile.setImageResource(mMobileStrengthId); 18628f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler mMobileType.setImageResource(mMobileTypeId); 187bcf6ef0b82c1daea43e03b8ad5af319ed324242aDaniel Sandler mMobileGroup.setContentDescription(mMobileTypeDescription + " " + mMobileDescription); 188cda096ebf3fac67daf36e775547c2a337374927bFabrice Di Meglio mMobileGroup.setVisibility(View.VISIBLE); 1892e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson } else { 1902e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson mMobileGroup.setVisibility(View.GONE); 1912e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson } 19228f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler 193061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn if (mIsAirplaneMode) { 194061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn mAirplane.setImageResource(mAirplaneIconId); 1958afcd149970c79054a3a16377834aa0aec35eee0Fabrice Di Meglio mAirplane.setVisibility(View.VISIBLE); 196061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn } else { 197061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn mAirplane.setVisibility(View.GONE); 198061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn } 199061d43c2386dd8222448bb1bec017bf9a2367a4eAndrew Flynn 2005172dc2f36f9c417befd0957ce2ae20f9d083a88Jorim Jaggi if (mIsAirplaneMode && mWifiVisible) { 2015172dc2f36f9c417befd0957ce2ae20f9d083a88Jorim Jaggi mWifiAirplaneSpacer.setVisibility(View.VISIBLE); 2025ccff81a642844138b144ad2cc339eba188812a0Daniel Sandler } else { 2035172dc2f36f9c417befd0957ce2ae20f9d083a88Jorim Jaggi mWifiAirplaneSpacer.setVisibility(View.GONE); 2045ccff81a642844138b144ad2cc339eba188812a0Daniel Sandler } 2055ccff81a642844138b144ad2cc339eba188812a0Daniel Sandler 206cd686b5b6d4166b510df8e32138479a9559bc117John Spurlock if (DEBUG) Log.d(TAG, 207fcc901c10bffdfb9c6b31e676dec36b47d949979John Spurlock String.format("mobile: %s sig=%d typ=%d", 20828f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler (mMobileVisible ? "VISIBLE" : "GONE"), 209fcc901c10bffdfb9c6b31e676dec36b47d949979John Spurlock mMobileStrengthId, mMobileTypeId)); 21028f89d40ee7bab93cf7b783f92dbb18bdc43e473Daniel Sandler 21114339c9edc2675d4757d572006625c2641db5653John Spurlock mMobileType.setVisibility(!mWifiVisible || mRoaming ? View.VISIBLE : View.GONE); 2122e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson } 2132e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson} 2142e347429dfcd03b0827c7506ba6305ab0d1f4951Christian Robertson 215