Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m Advertisement # Build an Adobe AIR Stopwatch Application Difficulty:IntermediateLength:LongLanguages: In this tutorial, we will build an Analog Timer AIR Application that we can use as a utility to time development work. We will be using a Custom Timer class that has Pause and Resume capabilities. This custom class will help you with a lot of Timer based applications as you'll see with a few examples. I created this project both with Flash CS4 and FlashDevelop. Although FlashDevelop can greatly speed up code development, everything can be done through Flash alone. If you'd like to try out FlashDevelop, you can download it from here. Note: If you plan to use Flash CS3 and do not already have Adobe AIR 1.5 set up with it, you can do so by following instructions from here. ## Step 1: Initial Setup Create a new folder anywhere you'd like and name it 'AnalogTimer'. Open Flash CS3/CS4 and hit CTRL + N to open the new Document window and choose Flash File (ActionScript 3.0). Click OK then save it as test.fla inside the 'AnalogTimer' folder. I've included the Inconsolata font with the source download. You might need to install this into your OS if you don't already have it. Note: if using Flash CS3, set the frame rate to 40. ## Step 2: Create the CustomTimer Class If you are using Flash for code development, hit CTRL + N and this time, choose ActionScript File. Click OK and save the file inside the 'AnalogTimer' folder and name the class CustomTimer.as. If you are using FlashDevelop for code development, open up FlashDevelop and hit CTRL + 2 to create a new ActionScript 3.0 file. Save it as CustomTimer in the same folder you have saved test.fla. ## Step 3: Setting up the Class and all of its Required Imports We will have it extend the flash.events.EventDispatcher class since it needs to dispatch custom events. Add the following lines of code: (Not sure what you're doing with this? Check out this quick introduction to document classes.) ## Step 4: Class Constants, Variables and the Constructor Right inside the class brackets, we will add the public constants, variables and the constructor method. These constants will be the values of the events dispatched. The variables will hold all the values we need to access about the CustomTimer's current status. The constructor will have one required parameter,$delay, of type Number, which will be assigned as the delay for the Timer object. The second parameter is optional: $repeatCount, which is the total number of times the timer is set to repeat. If this is not assigned, the default value is set to 0. Inside the constructor, we just assign the parameters to their class variable counterparts, _currentCount is set to zero and it then calls the init() method. Add the following lines of code: ## Step 5: The init() Method When the constructor calls the init() method, the _timer variable is assigned a new Timer class with a delay of 1 millisecond and adds an onTick listener for the 'TimerEvent.TIMER' event. I've included a copy of an EnterFrameCustomTimer class with the source download. If you plan on using more than 20 Timer classes at a time, with a delay parameter no smaller than 100 milliseconds, I would recommend to use the EnterFrameCustomTimer. Just increase the frameRate accordingly. Anything smaller than 100, e.g. 10 milliseconds, and the EnterFrameCustomTimer will be way off track unless you set the fps to 120. Add the following lines of code right below the constructor method: (Note: the TIMER event won't fire every millisecond exactly, but it's good enough for our needs. See this article on the 'Elastic Racetrack' for more details.) ## Step 6: External Controls Before we go into the onTick() method, let's add the external controls for the CustomTimer class. The start() method is in charge of starting the CustomTimer. As mentioned earlier, the _startTime is assigned the getTimer() value. _changeTime is then calculated by adding the _startTime + _delay. The _timer is then started and a CustomTimer.TIMER_STARTED event is dispatched. The pause() method checks to see if the _timer is running and if it is, stops it and dispatches a CustomTimer.TIMER_PAUSED event. The resume() method takes care of adjusting _changeTime by adding getTimer() + _timeLeft then dispatches a CustomTimer.TIMER_RESUMED event. You'll see that _timeLeft is updated every time the onTick() method is called. The quit() method stops the _timer, removes the TimerEvent.TIMER listener and then assigns null to the _timer variable, making it available for garbage collection. Add the following lines of code right below the init() method: Save the file before moving on. ## Step 7: The onTick() Method This method is called every millisecond once the CustomTimer has started. It only stops when pause() is called or if the _repeatCount is greater than zero, when the_currentCount has reached _repeatCount. Let's go through what goes on inside this method. First a local variable named 'now' is assigned the current getTimer() value. Then, _timeLeft is calculated by subtracting 'now' from _changeTime, remember, changeTime is initially assigned when start() is called. This variable is important since it provides information of when exactly it is within the duration of each iteration. A good example for this is when we pause the CustomTimer, with the information from _timeLeft, we can resume from where we paused. A conditional statement follows to see if now is greater than or equal to _changeTime. If it is, we add 1 to _currentCount and add _delay to _changeTime We then have a nested conditional statement to check if _repeatCount is greater than zero; if it isn't, we simply dispatch a CustomTimer.TICK event but if it is, we use another nested conditional statement: this time, we check if _currentCount is less than _repeatCount or not. If _currentCount is less than _repeatCount, we dispatch a CustomTimer.TICK and if _currentCount is greater than or equal to _repeatCount, it cleans up the Timer object by calling the quit() method. Two events are then dispatched - CustomTimer.TICK and CustomTimer.TIMER_FINISHED. Note: It is crucial to keep code that is always executed in best form or in other words 'optimized'. You wouldn't want to waste precious memory and processing time over unnecessary calculations. Add the following lines of code below the quit() method: ## Step 8: Getter Methods These two public methods allow read-only access to the two variables _delay and _currentCount. These properties are similar to the Timer class's delay and currentCount properties. Add the following lines of code: That completes our CustomTimer.as class. Make sure to save before moving forward. Your CustomTimer class should now look something like this: ## Step 9: CustomTimer Testing and Debugging Now that we have the CustomTimer class built, let's test to see if everything works the way it should. Open up test.fla which we created back in Step 2. Open up the Timeline (CTRL + ALT + T), click Frame 1 and hit F9; this should open up the script window. Enter the following code: Save and hit CTRL + ENTER to run the movie. You should see result like the following print out the to output window, with one line every second (except "tick 5" and "finished" should print out at the same time, as this is when the _currentCount has reached _repeatCount and both TICK and TIMER_FINISHED are dispatched): Now change 'repeat' to 0 then run the movie. This time the CustomTimer has no repeat limit and will simply go on indefinitely until the movie is stopped. It's the same as not supplying a second parameter to the CustomTimer class at instantiation. Go ahead and stop the movie. The CustomTimer class is identical to the native 'flash.utils.Timer' class, but adds the pause and resume functionality. ## Step 10: Testing Pause and Resume In the Timeline window, name the layer we used for scripting 'actions'. Create a new layer below the actions layer inside the Timeline and name it 'text'. Click Frame 1 of the 'text' layer and add a dynamic TextField in the middle of the stage and name it 'textField'. Make sure to use Inconsolata as the font and embed only the numerical glyphs. Set the font size to 50 and the color to 0x000000; also, the stage color should be 0xFFFFFF. Convert it to a movieClip (F8) and name it 'textMovie'. Name the instance on the stage 'text_mc'. In the Timeline, click the actions layer and click Frame 1, then hit (F9) to open the script window. Replace all the code inside the script window with the following lines of code: Save the file, run the movie and click on the stage. On your first click, it starts the countdown. The second click pauses the timer and, as you'll notice, when you click the stage the 3rd time, the timer resumes. After that, the pause and resume just cycles until the timer ends. We also trace the current status of the timer when it starts, when the stage is clicked, and when the timer finishes. Play with it for a moment. Try changing delay and repeat. Your result should be similar to the flash movie below with additional information printing on the output window: ## Step 11: A Simple CountDown Example Now that you're familiar with the CustomTimer class, let's create something a little more visual. Go ahead and drag a copy of countDown.fla from the source download into the 'AnalogTimer' folder. Double-Click the countDown.fla file inside the 'AnalogTimer' folder to open it. Open up the Timeline and the Stage windows. In the Timeline window, you will see three layers - the button layer, the clock layer, then the text layer. Inside the layer named 'button' is an instance of the Button component with an instance name of 'button_mc'. The clock layer holds two movieclips - an instance of seconds movieclip named 'seconds_mc' and an instance of border movieclip named 'clockFace_mc'. The text layer has a movieclip named 'text_mc' which contains a TextField named 'textField'. Note: If you are using Flash CS3, be sure to uncheck the box for Automatically Declare Stage Instances in the Publish Settings under Flash, under ActionScript Settings. ## Step 12: The CountDown.as Document Class In the 'AnalogTimer' folder where you saved the countDown.fla, create a new class and name it CountDown.as and add the following lines of code: ## Step 13: Add The Class Imports Right inside the package brackets, before the class declaration, insert the following lines of code: ## Step 14: Add The Public and Private Variables Add the following variables inside the Class brackets. The 4 public variables are references to the movieclips that are currently on the stage (see Step 11). The private variables are created when the class is instantiated. This is the same as what we had in test.fla. This time, we converted it into a class. You should be familiar with these variables from Step 10. ## Step 15: The Constructor Method This is where we put everything we need done when the Class is instantiated. Insert the following lines of code inside the CountDown Constructor Method brackets: ## Step 16: Event Listeners We just add the functions that are called when the events we are listening to are dispatched. Add the following lines right below the constructor method. ## Step 17: The Complete Class That completes our CountDown.as class, go ahead and save before moving on. Also, make sure to double-check your code for any errors. The CountDown.as Class should now look exactly like this: ## Step 18: Assigning The Document Class In Flash, open up the properties panel and assign 'CountDown' as the document class. Hit CTRL + ENTER to test the movie. If everything went well and the code in the document class has no errors, you should see something like this: Also, the output panel prints out the current value of the CustomTimer.currentCount. Again, you can try changing the _delay and _repeat properties inside the CountDown class to really get the feel of what's going on. ## Step 19: Setting Up for the Real Project We will now create the AIR utility you saw at the beginning of this tutorial. Make sure to close all previous work you've done and start fresh. We need to copy three files from the source download into the 'AnalogTimer' folder. They are the 'analogTimer.fla', The 'com' folder, and the 'MgOpenModernaBold.zip'. Drag a copy of this 'analogTimer.fla' file and save it in the 'AnalogTimer' folder. Open the 'MgOpenModernaBold.zip' and extract the 'MgOpenModernaBold.ttf' font into the 'AnalogTimer' folder. It should sit together with the analogTimer.fla. You don't need to install this font into your OS since we will assign this via Actionscript later. The 'com' folder. This is the Greensock Tweening engine that I've included for this tutorial. Copy this 'com' folder into the 'AnalogTimer' folder. For more information about the Greensock Tweening engine, take a look at www.greensock.com. Open the analogTimer.fla file that you saved in the 'AnalogTimer' folder. Inside the Timeline, you will see nine layers. It's important to get familiar with the movieclips associated with these layers because we will be working on them through the Document class that we will create later. 1. The first is the 'labels' layer, this layer is where we have 4 static texts "H", "M","S", & ".". They represent hours, minutes, seconds, and 1/10th seconds which describe the digits to their immediate right. 2. The second layer named 'container' only has an empty movieclip named 'analogContainer'. This movieclip will house the odometer engine which will be instantiated from the Odometer class which we will also create later. 3. The third layer is the 'mask' layer. This layer contains an instance of mask named 'digitMask'. We don't have to convert this into a mask inside the flash file and worry about it's order of position since we will assign it as a mask via actionscript later on. To see the 'digitMask' movieclip, you can hide the container layer above it. 4. The fourth layer named 'start' houses an instance of playButton also named 'playButton'. 5. The fifth layer named 'pause' and has a movieclip instance of the pauseButton also named 'pauseButton'. This movieclip sits exactly below 'playButton'. To see it, hide the layer for 'playButton'. 6. The sixth layer is named 'reset', it only contains a movieclip instance of the resetButton named 'resetButton'. 7. The seventh layer named 'minimize' has a movieclip instance of minimizeButton named 'minimizeButton'. 8. The eighth layer is named 'close' and has a movieclip instance of closeButton named 'closeButton'. 9. The last layer named 'bg' has an instance of backGround named 'background'. The analogTimer.fla should be set to 40 fps with the dimensions of 243 x 22 pixels. Again, if you are using Flash CS3, make sure to uncheck the 'Automatically declare stage instances' from Publish Settings>Flash>ActionScript Settings. Still within the Flash tab, click the player dropdown menu, choose Adobe AIR 1.5, and click 'OK'. Press Settings from the Player option; for the window style, choose Custom Chrome (transparent). Save the changes. ## Step 20: The Time Enumeration Class This project will have a total of 5 classes including the CustomTimer class. Let's start with the smallest to keep things clear. Create a new Class and name it Time. This is a very simple class, all it does is hold public static constants that represent values of time. Now whenever I need a value of time, e.g. 1 hour (3600000 milliseconds), all I have to do is access Time.ONE_HOUR which is a lot more readable than its numerical value. This Class will be used in conjuction with 2 major classes later. Add the following lines of code: Note: all the classes that we will create should be saved into the same folder ('AnalogTimer'). ## Step 21: Testing The Time Class Open up a new Flash file, name it timeTest.fla, and save it inside the AnalogTimer folder. It should be alongside the Time.as class. Inside the script window, type in: If the result is correct, go ahead and close the file. ## Step 22: The Digit Class Create another class and call it Digit.as. This class is also fairly simple. It takes two required parameters, the first is$index which has an unsigned integer value and second, $textFormat which is assiged a textFormat instance and creates the numbers you see that are animated when the timer is started. Also, the numbers are positioned in the center of each instance. Add the following lines of code: ## Step 23: Testing The Digit Class Open up a new Flash file and name it digitTest.fla and save it inside the AnalogTimer folder. It should be alongside the Digit.as class. Right-Click the library tab and select New Font. Choose the installed 'Inconsolata' font and name it 'Inconsolata'. Check the box for Export for Actionscript and click 'OK' twice. Inside the script window, type in: You should see a red '4' on the stage. When you're done, go ahead and close the file. ## Step 24: Odometer Class Imports and Variables This is the main animation engine. You should visualize this class as one independent mechanical section for the AnalogTimer application. When you look at the final preview, you will see seven Odometers. Create a new class and name it Odometer.as. Add the following code: Inside the class brackets are 12 private variables. The _format variable holds a TextFormat instance that will be passed to the Digit class. When you saw the preview, did you notice the 1/10th second's color is red? That's what we need this for. The _digits variable is an array that will hold all the Digit classes that we will instantiate later. _index is an unsigned integer that we increment by 1 every time the CustomTimer dispatches a 'TICK' event. It points into the Digit instance in the_digits array which becomes the next target for animation. _startX, _centerX, and _endX are assigned positions for the Digits. _startX is where the numbers animate coming from the top. _centerX is where they pause showing the current value of the time it represents, and _endY is where they animate to coming from _centerX. The _limit variable, an unsigned integer, gets either a value of 10 or 6, depending on what speed of CustomTimer we assign for this Odometer instance. I'll explain more later when we get to its assignment. _speed is a Number variable that is assigned the delay value of the CustomTimer that is passed in as a parameter. _customTimer is assigned the CustomTimer we pass in from the constructor. It triggers the animation for the Odometer. _currentTarget and _previousTarget are Sprite variables that are assigned with Digit classes. They are used when pause and resume are called. The _rollSpeed variable of type Number, is assigned the proper speed the Digit class is animated from _startX to _centerX, to _endX. ## Step 25: Odometer Class Constructor Method As with all constructors' methods, we only put everything that needs to be prepared at instantiation inside of it. Add the following lines of code right below the _rollSpeed variable: As soon as an instance is created, _customTimer is assigned a reference to the CustomTimer passed as a parameter. It then assigns the value of _customTimer's delay to _speed. The setRollSpeed() and setLimit() functions are then called and finally, event listeners are added for Event.ADDED_TO_STAGE and Event.REMOVED_FROM_STAGE. ## Step 26: Odometer Class The setRollSpeed Method This method checks to see if the _speed variable is less than or equal to Time.ONE_TENTH_SECOND (100 milliseconds). If it is, _rollSpeed is set to Time.ONE_TENTH_SECOND. If _speed is anything but less than or equal to Time.ONE_TENTH_SECOND, _rollSpeed is set to Time.ONE_SECOND / 2 (500 milliseconds). It then converts _rollSpeed to a fractional value required for TweenLite. Ex. Time.ONE_TENTH_SECOND is 100. We need to divide it with Time.ONE_SECOND to convert it to '0.1'. Add the following lines of code right after the constructor method: ## Step 27: Odometer Class The setLimit Method It's a simple method, all it does is set _limit according to the value of _speed. A good example is Time.TEN_MINUTES, it represents the "tens" column in the minutes, and as you know, these only go from 0-5. You'll see how we use this when we get to the startTweens() method. Add the following lines of code below the setRollSpeed method: ## Step 28: Odometer Class The init Method This method is called when the instance gets added to the stage. First it removes the Event.ADDED_TO_STAGE listener and then adds listeners for the _customTimer's events - TICK, TIMER_PAUSED, and TIMER_RESUMED. Then it calls the createOdometer() method. Add the following lines of code: ## Step 29: Odometer Class The createOdometer Method Within this method, _digits is assigned a new Array instance. _format is then assigned a TextFormat. If _speed is equal to Time.ONE_TENTH_SECOND, _textFormat is assigned RED as the color and BLACK if not. We then loop to the value of _limit and call createDigits() passing the current iteration as the parameter. Add the following lines of code: ## Step 30: Odometer Class The createDigits Method As you already know, every time this method is called, it comes with a different$index value ranging from 0 to the value of _limit (either 6 or 10, refer to step 24). It checks to see if $index is equal to 0; if it is, digit is positioned on _centerY. If$index isn't equal to 0, digit is positioned on _startY. digit is then added inside Odometer and pushed into the _digits array for reference later.

Add the following lines of code:

## Step 31: Odometer Class The roll Method

As you may recall, this is the method called everytime a TICK event is dispatched by _customTimer. _index is incremented by 1 and then checked if the current value is greater than or equal to the length of _digits. If it is, _index is assigned 0 again. A local variable named target of type Digit is then assigned the Digit that resides within the current _index of the _digits array. When the class is instantiated, _index, of type uint is assigned no value which defaults to 0. This means that the first animation you will see when the application starts is 0 moving out from _centerY to _endY and 1 moving in from startY to _centerY. The target is then positioned on _startY so everytime target is animated, it starts from the right position. After all the setup, startTweens () is called passing target as the parameter.

Add the following lines of code:

## Step 32: Odometer Class The startTweens Method

Everytime this method is called, a local variable named previous is created and _currentTarget is assigned the $target parameter. It then loops through all the Digit instances stored inside _digits. Once the$target has matched the current Digit in _digits, _limit is tested to see if its value is 10 or not. If _limit is 10 and the current iteration (i) is equal to 0, previous is assigned 9, if the current iteration isn't equal to 0, previous is assigned one less than i.

On the other hand, if _limit is not equal to 10 (meaning it's equal to 6), if the current iteration is equal to 0, previous is assigned 5, if not, previous is assigned i - 1. _previousTarget is then assigned _digits[previous].

We need _currentTarget & _previousTarget assigned here so that any time the application is paused, if we ever need to resume, we know which Digits were animating.

Note also that once _previousTarget has been located in _digits, we break out of the loop to save resources.

TweenLite is then instantiated to animate both _currentTarget & _previousTarget.

## Step 33: Odometer Class The onPause & onResume Methods

The onPause() method simply stops all the tweens of all the Digits that are currently animating by looping through all the Digits in _digits and calling the TweenLite.killTweensOf() method, assigning digit as the parameter.

The onResume() method checks three conditions - whether _currentTarget has been assigned a value, whether _currentTarget's y position is less than _centerY, and whether _currentTarget's y position is greater than or equal to _startY. If those conditions are all true, TweenLite is then called to animate _currentTarget from its current position to _centerY.

_previousTarget is then also checked for 3 conditions, if it has been assigned, if its y position is less than _endY and greater than _startY. If all those conditions are met, _previousTarget is animated from its current position to _endY.

Add the following lines of code:

## Step 34: Odometer Class The removeRef Method

This method is called whenever the class is removed from the stage. It pretty much takes care of clean up. Whenever the app is reset, it disposes of the old Digits and CustomTimers and starts anew.

Add the following lines of code:

The Complete Odometer Class should now look exactly like below:

## Step 35: Odometer Class Testing

Open up a new Flash file and name it odometerTest.fla and save it inside the AnalogTimer folder. It should be along with the Odometer.as class.

Add an Inconsolata font exactly as you did in Step 23.

Inside the script window, type:

You should see seconds rolling on the stage. When you're done, go ahead and close the file.

Inside the Odometer Class, on createOdometer() method, change the Font assigned to the TextFormat from 'Inconsolata' to 'MGOpen'.

The createOdometer() method should now look like this:

Save the class before moving on.

## Step 36: AnalogTimer Class Imports and Variables

The final class, this will also be the document class for our analogTimer.fla.

The first 8 public variables are references to the stage assets (see Step 19). Right below those is an [embed] metatag for the font I've included, with the source download assigned to a private variable named MgOpen of type Class. This font was extracted to the 'AnalogTimer' folder earlier during set up.

The _timerArray variable is an array the class will use to reference all the CustomTimer instances.

The _adjustment variable holds an unsigned integer value of 8 that we will use to position each Odometer instance on the stage.

Create a new class named AnalogTimer.as and add the following lines of code:

## Step 37: AnalogTimer Class buildApp Method

This method is called as soon as the AnalogTimer class is instantiated. It accurately describes its pupose.

The playButton is added to the stage to ensure that it is on top of the pauseButton. Event listeners are then added to the background, playButton, minimizeButton, & closeButton. The alpha property of _pauseButton is set to 0 to make it invisible, and _playButton's alpha is set to 1.

A new array is then assigned to _timerArray.

The analogContainer is then checked to see if it has more than one child. Remember, we have one graphic object as its child: the gradient rectangle which we use as background for the digits. If analogContainer's children is more than 1, we loop backwards and remove all of them except for the gradient rectangle object. This happens when reset is called.

We then create a local array variable named sequence. Inside this are smaller arrays with Time values and references to the children of digitMask. We loop through sequence array and for every iteration, we create a CustomTimer instance with the value of the current iteration in the sequence array in position 0: sequence[current_iteration][0]. We then create an instance of Odometer and assign the CustomTimer isntance as its parameter. The Odometer instance is then added as a child to the analogContainer movieclip on the stage and positioned based on the current iteration in sequence in position 1, then _adjustment is applied. The digitMask is then set as the mask for analogContainer.

Add the following lines of code right below the last private variable:

## Step 38: AnalogTimer Class AIR Application Drag Functionality

These three methods work together to drag the application. When stage.nativeWindow.startMove() is triggered, the whole AIR app will move around the desktop. They should be self-explanatory.

Add the following lines of code:

(The appPress and appRelease event listeners were added to the buildApp method in Step 37.)

## Step 39: AnalogTimer Class startTimer() Method

When the playButton is clicked, playTimer() is called and all the CustomTimer instances in _timerArray are told to start.

Add the following lines of code:

## Step 40: AnalogTimer Class playTimer() Method

Here, it removes the event listener for playButton to start the CustomTimer. The resetButton is then assigned a listener to reset the application and the tweenTarget method is called assigning playButton, pauseButton and the enablePauseButton method as parameters.

Add the following lines of code:

## Step 41: AnalogTimer Class tweenTarget and nextTween Methods

This methods should be positioned as the last two methods for this class. We go over it now to explain what happens when tweenTarget() is called.

Inside tweenTarget(), the first parameter is tweened to an alpha of 0. When the tween completes, nextTween is called sending the second and third parameters. The overwrite property is set to false to ensure the tween completes before nextTween is called.

Inside nextTween, the first parameter is added to the stage to make sure that it is currently on top for visibility. TweenLite is then called to animate it to an alpha of 1. The \$function parameter is then called when nextTween completes.

You can feel the effect of this if you try to click like crazy on the start and pause buttons. The animation needs to complete before you can click the button again. You'll see what goes on the enablePauseButton() method soon.

Add the following lines of code:

## Step 42: AnalogTimer Class pauseTimer Method

Here, the listener for pauseTimer is removed since the application has already paused. The tweenTarget method is then called again with pauseButton, playButton, & enablePlaybutton() as parameters. It then loops for every CustomTimer instance in _timerArray and calls pause() on them.

Add the following lines of code:

## Step 43: AnalogTimer Class resumeTimer Method

This method calls playTimer() and then loops for every CustomTimer and calls resume().

Add the following lines of code:

## Step 44: AnalogTimer Class enablePlayButton & enablePauseButton Methods

These methods are called when nextTween() completes. They simply add event listeners to the buttons to enable pause and resume. Again, this is the reason why the animation needs to complete before you can click the alternate button.

Add the following lines of code:

## Step 45: AnalogTimer Class resetTimer Method

Inside this method is what goes on when the resetButton (if active) is clicked. All listeners for the resetButton, pauseButton, and playButton are removed.

It then applies animation to the resetButton, playButton, and analogContainer. Notice the soft fade in and out of the numbers, playButton, resetButton and pauseButton whenever you reset the application.

After all that, the buildApp() method is called to create a new set of Odometers and CustomTimers.

Add the following lines of code:

## Step 46: AnalogTimer Class minimizeTimer & closeTimer Methods

These methods are responsible for minimizing and closing the AIR application. Again, they are simple and straight forward.

Add the following lines of code:

That's it! We're done! Your AnalogTimer Class should now look like this:

Go ahead and assign AnalogTimer as the document class for analogTimer.fla. If everything went well, you should have something like the preview with the minimize and close buttons enabled.

Hit Shift + F12, the Digital Signature window will pop up. Click 'Create' for the certificate. Fill out all the fields and save it into the 'AnalogTimer' folder.

Type in the password you chose when you created the Self-signed Digital Certificate and click 'OK'. You now have an AIR application published and ready to install on your computer.

## Conclusion

I hope this tutorial helped you understand some of the possibilities of use for the CustomTimer class. Thanks so much for reading!