Android source Deskclock (iv)

Source: Internet
Author: User
Tags gety xdiff

I. Overview

Before writing three time to spare a bend, through the Deskclock this project simple implementation of the reinforcement + heat repair, in this article continue to return to the regular analysis of the source code. In two, the main entrance of Deskclock was analyzed, and the conversion of four main functions fragment From this beginning, we begin to analyze these four functions. Start with the fragment of the clock function.

Two. Source Code Analysis

1.onCreateView

here, based on the sequence analysis of the clockfragment life cycle, the first is Oncreateview, where the job is to load the layout file, initialize the control adapter, and declare the listener.

Here the layout of the horizontal screen and vertical screen two, the overall structure is a ListView-based, mounted header,footer,menu and select the city composition. So in addition to the generic controls, It is necessary to distinguish the vertical screen when initializing the control. Here the layout of the clock in the horizontal screen when it is separated from the ListView, while in the vertical screen as a ListView headerview exist, so the source of the first to get the view of the clock in the horizontal screen, If the empty description is currently vertical, the layout is inflate out to hang onto the headerview of the ListView.

from the above source to see the horizontal screen when the clock on the view and vertical screen when the ListView has set the same touchlistener, From listening to the name can feel is long press into the role of night mode. Why Android provides long-press listening (Setonlongclicklistener), why also Sao to write long-press listening, of course, their own long-press monitoring can be customized more detailed rules, For example, long-press time, long-time sliding fault-tolerant processing and so on. During initialization, the fault-tolerant offset and long-press-triggered time values are populated by the configuration in Viewconfiguration, and when the user presses the screen after listening to the handler Post a delay message into the night Mode page to the message queue and record the current down coordinates, and then, if the user slides, calculates the sliding offset based on the touch coordinates of the record, and when the offset is greater than the fault tolerance, the previous message is The queue is removed. If the user does not reach the setting and leaves the screen when it is pressed, the remove message from the default will also be executed.
Ontouchlistener Longpressnightmode = new Ontouchlistener () {private float mmaxmovementallowed =-1;            private int mlongpresstimeout =-1;            Private float Mlasttouchx, mlasttouchy;                    @Override public boolean OnTouch (View V, motionevent event) {if (mmaxmovementallowed = =-1) {                    mmaxmovementallowed = Viewconfiguration.get (Getactivity ()). Getscaledtouchslop ();                Mlongpresstimeout = Viewconfiguration.getlongpresstimeout (); } switch (Event.getaction ()) {case (Motionevent.action_down): Lo                        ng time = Utils.gettimenow ();                                Mhandler.postdelayed (New Runnable () {@Override public void run () {                            StartActivity (New Intent (Getactivity (), screensaveractivity.class)); }}, MlongpresstImeout);                        Mlasttouchx = Event.getx ();                        Mlasttouchy = Event.gety ();                    return true;                        Case (Motionevent.action_move): Float Xdiff = Math.Abs (Event.getx ()-mlasttouchx);                        float Ydiff = Math.Abs (Event.gety ()-mlasttouchy); if (Xdiff >= mmaxmovementallowed | | Ydiff >= mmaxmovementallowed) {Mhandler.removecallba                        Cksandmessages (NULL);                    } break;                Default:mHandler.removeCallbacksAndMessages (NULL);            } return false; }        };

2.onResume

Register Sharedpreferencechange Monitoring at this time, when the user modifies the clock style in the settings, the adapter is updated, Update the style of item for all city time in the ListView. and the current clock style is also set in the Onresume, the user set the clock style back to the main page will recall the Onresume, so that all the style changes will take effect.

    public void onsharedpreferencechanged (Sharedpreferences prefs, String key) {        if (key = = Settingsactivity.key_clock_ STYLE) {            Mclockstyle = prefs.getstring (Settingsactivity.key_clock_style, mdefaultclockstyle);            Madapter.notifydatasetchanged ();        }    }
        Sharedpreferences Sharedpref = preferencemanager.getdefaultsharedpreferences (context);        String Defaultclockstyle = Context.getresources (). getString (R.string.default_clock_style);        String style = Sharedpref.getstring (Clockstylekey, defaultclockstyle);        View Returnview;        if (Style.equals (Clock_type_analog)) {            digitalclock.setvisibility (view.gone);            Analogclock.setvisibility (view.visible);            Returnview = AnalogClock;        } else {            digitalclock.setvisibility (view.visible);            Analogclock.setvisibility (view.gone);            Returnview = DigitalClock;        }

turn on an asynchronous task that updates the date UI every quarter. It is no problem to look at this point, but every time you capture a change in the broadcast and UI Onresume to update the date, then why do you want to turn on this duplicate check. Not just the sync date, The sync time and sync alarms below are double-duplicated (labeled * * places). I get less than what Google engineers do, hoping to communicate with children's shoes that feel like they do.

Utils.setquarterhourupdater (Mhandler, Mquarterhourupdater);
    Thread that runs on every quarter-hour and refreshes the date.    Private final Runnable Mquarterhourupdater = new Runnable () {        @Override public        void Run () {            //Update the main and world Clock dates            utils.updatedate (Mdateformat, mdateformatforaccessibility, mclockframe);            if (madapter! = null) {                madapter.notifydatasetchanged ();            }            Utils.setquarterhourupdater (Mhandler, mquarterhourupdater);        }    ;
There's still a few system broadcasts to update the date and city list. Because the clock UI still has alarm information, listen to custom alarm broadcasts to refresh the display of the alarm information.

    Private final Broadcastreceiver mintentreceiver = new Broadcastreceiver () {@Override public void on            Receive (context context, Intent Intent) {String action = intent.getaction (); Boolean changed = Action.equals (intent.action_time_changed) | | Action.equals (intent.action_timezone_changed) | |            Action.equals (intent.action_locale_changed);                if (changed) {utils.updatedate (Mdateformat, mdateformatforaccessibility,mclockframe);  if (madapter! = null) {//*changed may modify the need for showing the Home city if (Madapter.hashomecity ()! = Madapter.needhomecity ())                    {Madapter.reloaddata (context);                    } else {madapter.notifydatasetchanged (); }//Locale change:update Digital clock format and//Reload the cities list with nEW Localized names if (Action.equals (intent.action_locale_changed)) {if (mdigit Alclock! = null) {Utils.settimeformat ((textclock) (Mdigitalc                                           Lock.findviewbyid (R.id.digital_clock)), (int) context.getresources ().                        Getdimension (r.dimen.bottom_text_size));                        } madapter.loadcitiesdb (context);                    Madapter.notifydatasetchanged ();            }} utils.setquarterhourupdater (Mhandler, Mquarterhourupdater); } if (changed | | action.equals (alarmnotifications.system_alarm_change_action)) {Utils.refreshal            Arm (getactivity (), mclockframe); }        }    };

finally registered a database change monitoring, in fact, this listener with the above broadcast is repeated, when the latest alarm clock time has been changed and will receive a refresh alarm UI broadcast and database monitoring, they are doing the same operation. (**)

        Activity.getcontentresolver (). Registercontentobserver (                Settings.System.getUriFor (Settings.System.NEXT_ alarm_formatted),                false,                malarmobserver);
    Private final Handler Mhandler = new Handler ();    Private final Contentobserver malarmobserver = new Contentobserver (mhandler) {        @Override public        void OnChange ( Boolean selfchange) {            utils.refreshalarm (ClockFragment.this.getActivity (), mclockframe);        }    };

3.onPause

in the Onresume registered a series of services, with the relative deserved to be in the onpause inside to unbind and Onresume registration corresponding services.

    @Override public    void OnPause () {        super.onpause ();        Mprefs.unregisteronsharedpreferencechangelistener (this);        Utils.cancelquarterhourupdater (Mhandler, mquarterhourupdater);        Activity activity = getactivity ();        Activity.unregisterreceiver (mintentreceiver);        Activity.getcontentresolver (). Unregistercontentobserver (Malarmobserver);    }

4.AnalogClock

Two dials are provided in the setting, one is the digital dial, the textclock used in the digital dial in the Deskclock, and the dial is custom. The dial is drawn here. Since it is custom, it is necessary to allow time to synchronize the system time, The main thing here is to listen to the Android.intent.action.TIME_TICK broadcast, which is emitted by the system every minute of the hour and can be used to calibrate the timing time. Turn on an asynchronous task that executes every 1000 milliseconds to get the changes to the current time update pointer.

    Private final Runnable Mclocktick = new Runnable () {        @Override public        void Run () {            ontimechanged ();            Invalidate ();            AnalogClock.this.postDelayed (Mclocktick, +);        }    ;
    Private final Broadcastreceiver mintentreceiver = new Broadcastreceiver () {        @Override public        void OnReceive ( Context context, Intent Intent) {            if (intent.getaction (). Equals (intent.action_timezone_changed)) {                String tz = Intent.getstringextra ("Time-zone");                Mcalendar = new Time (Timezone.gettimezone (TZ). GetID ());            }            Ontimechanged ();            Invalidate ();        }    };
the above two methods are used to ensure that the deskclock time is consistent with the system. Personal feeling here listening to Time_tick broadcast some superfluous ( * *), Because asynchronous tasks go through the calibration time each time they are executed. The first thing to do when the ontimechanged is called is to calibrate the current time, change the pointer's properties, Wait for the invalidate to redraw. The last part of the setcontentdescription is to turn on the talkback function in the system accessibility after setting the content description The Android system will read the contents of the Set TTS ( The same as the RTL is a less popular usage).

    private void Ontimechanged () {        mcalendar.settonow ();        if (Mtimezoneid! = null) {            mcalendar.switchtimezone (Mtimezoneid);        }        int hour = Mcalendar.hour;        int minute = Mcalendar.minute;        int second = Mcalendar.second;      Long Millis = System.currenttimemillis ()%;        Mseconds = second;//(float) ((second * + Millis)/166.666);        Mminutes = minute + second/60.0f;        Mhour = hour + mminutes/60.0f;        Mchanged = true;        Updatecontentdescription (Mcalendar);    }

5.ScreenSaverActivity

Screensaveractivity is still more interesting, when the phone in the charging state screensaver will run on the Lock screen page, So it is necessary to use a variety of broadcasts to control the various states of screensaver. First in the OnStart when registration time related, charging related and user unlock screen broadcast, register to monitor the data of the next alarm clock database changes observer.

        Intentfilter filter = new Intentfilter ();        Filter.addaction (intent.action_power_connected);        Filter.addaction (intent.action_power_disconnected);        Filter.addaction (intent.action_user_present);        Filter.addaction (intent.action_time_changed);        Filter.addaction (intent.action_timezone_changed);        Registerreceiver (mintentreceiver, filter);        Getcontentresolver (). Registercontentobserver (                Settings.System.getUriFor (Settings.System.NEXT_ALARM_ formatted),                false,                msettingscontentobserver);

If you hear a broadcast with time or time zone changes, update the UI data for the date and the alarm. If you listen to the user unlock screen, finish off yourself. If the current device is connected to an external power source, start the mode that has survived on the lock screen.

    Private final Broadcastreceiver mintentreceiver = new Broadcastreceiver () {@Override public void onrece                    Ive (context context, Intent Intent) {Boolean changed = Intent.getaction (). Equals (intent.action_time_changed) ||            Intent.getaction (). Equals (intent.action_timezone_changed);                if (Intent.getaction (). Equals (intent.action_power_connected)) {Mpluggedin = true;            Setwakelock ();                } else if (Intent.getaction (). Equals (intent.action_power_disconnected)) {Mpluggedin = false;            Setwakelock ();            } else if (Intent.getaction (). Equals (Intent.action_user_present)) {finish ();                } if (changed) {utils.updatedate (Mdateformat, mdateformatforaccessibility, Mcontentview);                Utils.refreshalarm (Screensaveractivity.this, Mcontentview);            Utils.setmidnightupdater (Mhandler, Mmidnightupdater);}        }    }; 
How does this make screensaver run on the lock screen? Several layout parameter properties need to be introduced first.

1) Flag_dismiss_keyguard unlock screen, run on the lock screen on the basis of

2) flag_show_when_locked Let the current view draw on the Lock screen page, click Back to see the lock screen page

3) flag_allow_lock_while_screen_on lock screen when the screen is enabled

4) The flag_keep_screen_on keeps the screen open, unaffected by hibernation.

5) Flag_fullscreen make the current view full screen


These properties are distinguished by the different values of the 16 binary flag bits, which are stored through or operations. (e.g. Flag_dismiss_keyguard | Flag_show_when_locked is actually 0x00400000 | 0x00080000 = 0x00480000, so the two attributes are superimposed.) So the current mflags of the total property is to unlock the screen + in the lock screen when the display + screen on when the lock screen + keep the screen open.

    Private final int mflags = (WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD            | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED            | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON            | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

First, the screensaver set the full-screen parameters, if the current page to run on the lock screen, through or save the operation, the above mflags all the properties are loaded in. What if you want to cancel the previous operation? To cancel, you need to take the previous or existing expression and the value of the mflags all to the inverse operation.

    private void Setwakelock () {        Window win = GetWindow ();        Windowmanager.layoutparams winparams = Win.getattributes ();        Winparams.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;        if (Mpluggedin)            winparams.flags |= mflags;        else            winparams.flags &= (~mflags);        Win.setattributes (Winparams);    }
as long as the front received a broadcast connected to the external power, the screensaver mode will be turned on, if I turn on the power before screensaveractivity, And after you turn on screensaveractivity, aren't you going to receive this broadcast? Of course, this is also handled in this case, when the screensaveractivity in Onresume will get the current state of the battery, if the current plug-in or USB or large wireless charging will turn on screensaver mode.
        Intent chargingintent =                registerreceiver (null, New Intentfilter (intent.action_battery_changed));        int plugged = Chargingintent.getintextra (batterymanager.extra_plugged,-1);        Mpluggedin = plugged = = Batterymanager.battery_plugged_ac                | | plugged = BATTERYMANAGER.BATTERY_PLUGGED_USB                | | plugged = = batterymanager.battery_plugged_wireless;
Three. Summary

This article roughly analyzes the main functions of the clock part of the Deskclock, of course, there are some details where there is no explanation, such as the AnalogClock dial hand drawing, Screensaveractivity the movement of the dial in the middle of the day. Also found some of the personal feel less appropriate code logic (tagged * * Date time Alarm UI Data synchronization part), want to have ideas (no matter the praise) of the children's shoes a lot of communication.



Reprint Please specify source: http://blog.csdn.net/l2show/article/details/47298463

Android source Deskclock (iv)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.