Blograby

Fake Call (Resources & Styles)

The Fake Call app makes your phone appear to receive an incoming call at a time you specify. You can use this as an excuse to get out of a bad date or an otherwise-unpleasant situation. Simply pretend to answer the fake call, make up some plausible story about needing to leave as a result of the phone call, and leave!

This app has three pages:

Unlike the preceding app, this intentionally does not use the page transition animation when navigating from one page to another, because that would interfere with the illusion that the real Phone app is being used. In this app, multiple pages are used just as a nice way to structure the code rather than as a metaphor that benefits users.

The Main Page

Fake Call’s main page, pictured in Figure 9.1

FIGURE 9.1 The main page is a simple form to fill out, much like the main page in the “In Case of Emergency”app.

The User Interface

Listing 9.1 contains the XAML for the main page.

[code]

<phone:PhoneApplicationPage
x:Class=”WindowsPhoneApp.MainPage”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
xmlns:phone=”clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone”
xmlns:shell=”clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone”
xmlns:local=”clr-namespace:WindowsPhoneApp”
xmlns:toolkit=”clr-namespace:Microsoft.Phone.Controls;
➥assembly=Microsoft.Phone.Controls.Toolkit”
FontFamily=”{StaticResource PhoneFontFamilyNormal}”
FontSize=”{StaticResource PhoneFontSizeNormal}”
Foreground=”{StaticResource PhoneForegroundBrush}”
SupportedOrientations=”PortraitOrLandscape”
shell:SystemTray.IsVisible=”True”>
<!– Add some items to the page’s resource dictionary –>
<phone:PhoneApplicationPage.Resources>
<!– A margin for the standard header –>
<Thickness x:Key=”PhoneTitlePanelMargin”>24,16,0,12</Thickness>
<!– The tweaked application title style –>
<Style x:Key=”PhoneTextTitle0Style” TargetType=”TextBlock”>
<Setter Property=”FontFamily”
Value=”{StaticResource PhoneFontFamilySemiBold}”/>
<Setter Property=”Foreground”
Value=”{StaticResource PhoneForegroundBrush}”/>
<Setter Property=”FontSize” Value=”{StaticResource PhoneFontSizeMedium}”/>
<Setter Property=”Margin” Value=”-1,0,0,0”/>
</Style>
<!– The tweaked page title style –>
<Style x:Key=”PhoneTextTitle1Style” TargetType=”TextBlock”>
<Setter Property=”FontFamily”
Value=”{StaticResource PhoneFontFamilySemiLight}”/>
<Setter Property=”Foreground”
Value=”{StaticResource PhoneForegroundBrush}”/>
<Setter Property=”FontSize”
Value=”{StaticResource PhoneFontSizeExtraExtraLarge}”/>
<Setter Property=”Margin” Value=”-3,-10,0,0”/>
</Style>
<!– A style for text blocks that act as a label for a text box –>
<Style x:Key=”LabelStyle” TargetType=”TextBlock”>
<Setter Property=”Foreground” Value=”{StaticResource PhoneSubtleBrush}”/>
<Setter Property=”Margin” Value=”24,17,24,-5”/>
</Style>
</phone:PhoneApplicationPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height=”Auto”/>
<RowDefinition Height=”*”/>
</Grid.RowDefinitions>
<!– The standard header, with some tweaks –>
<StackPanel Grid.Row=”0” Margin=”{StaticResource PhoneTitlePanelMargin}”>
<TextBlock Text=”FAKE CALL” Style=”{StaticResource PhoneTextTitle0Style}”/>
<TextBlock Text=”call settings”
Style=”{StaticResource PhoneTextTitle1Style}”/>
</StackPanel>
<!– Scrollable pane (for the sake of the landscape orientation) –>
<ScrollViewer Grid.Row=”1”>
<!– A button and three text block / text box pairs stacked vertically –>
<StackPanel>
<Button Content=”wait for call” HorizontalAlignment=”Left”
Margin=”12,13,0,18” Click=”WaitForCallButton_Click”/>
<TextBlock Text=”Time to receive call”
Style=”{StaticResource LabelStyle}”/>
<toolkit:TimePicker x:Name=”TimePicker” local:Tilt.IsEnabled=”True”
ValueChanged=”TimePicker_ValueChanged”
Margin=”{StaticResource PhoneHorizontalMargin}”/>
<TextBlock Text=”Incoming phone number”
Style=”{StaticResource LabelStyle}”/>
<!– Use the Number input scope so we also get parentheses and a dash –>
<TextBox x:Name=”PhoneNumberTextBox” InputScope=”Number”
Margin=”{StaticResource PhoneHorizontalMargin}”
GotFocus=”TextBox_GotFocus” KeyDown=”TextBox_KeyDown”/>
<TextBlock Text=”Carrier name” Style=”{StaticResource LabelStyle}”/>
<TextBox x:Name=”CarrierTextBox” InputScope=”PersonalFullName”
Margin=”{StaticResource PhoneHorizontalMargin}”
GotFocus=”TextBox_GotFocus” KeyDown=”TextBox_KeyDown”/>
</StackPanel>
</ScrollViewer>
</Grid>
</phone:PhoneApplicationPage>

[/code]

Notes:

FIGURE 9.2 The time picker makes it easy to choose a time with taps and swipes.

The time picker requires two specific images to be included in your project!

As with the date picker, you must include two images from the Silverlight for Windows Phone Toolkit in your project (and mark them with a Build Action of Content).These images are ApplicationBar.Check.png and ApplicationBar.Cancel.png, and they must be placed in a folder called Toolkit.Content in the root of your project.

Resources

Windows Phone apps can have two types of resources. One type, often called binary resources, consists of things like image files, audio/video files, and font files. Sometimes these are embedded into your DLL (when the Build Action is set to Resource) and sometimes these are placed as loose files inside your .xap file (when the Build Action is set to Content). The choice of how to package binary resources is sometimes dictated by their consumer (such as the application bar requiring loose files), and sometimes dictated by how you wish to localize the resources in order support multiple languages and regions. As you’ve seen in previous chapters, various elements support referencing binary resources via URIs.

Defining XAML Resources

The XAML files in this app, such as MainPage.xaml in Listing 9.1, make use of the other type of resources. They are often called XAML resources because they are typically defined in XAML, but this book generally refers to them as simply resources, using the term binary resources to refer to the other kind.

A resource is an arbitrary object stored in an element’s Resources property. Such objects can be anything—a number, a brush, or a complex object such as a style. The first resource defined in Listing 9.1 is a thickness, the data type used by margins and padding:

[code]<Thickness x:Key=”PhoneTitlePanelMargin”>24,16,0,12</Thickness>[/code]

The point of defining a resource is to separate and consolidate styling information, much like using Cascading Style Sheets (CSS) to control colors and styles in a webpage rather than hard-coding them on individual elements. The Resources property is a dictionary (usually called a resource dictionary), so adding a child element is equivalent to adding a new key/value pair to the dictionary in C#. The value is the element, and the key is the string specified via the x:Key attribute. Everything placed in a resource dictionary must have a key.

Referencing XAML Resources

Resources are referenced with the familiar StaticResource syntax. Each resource is often referenced by more than one element, although the thickness resource with the PhoneTitlePanelMargin key happens to be referenced only once:

[code]

<StackPanel Grid.Row=”0” Margin=”{StaticResource PhoneTitlePanelMargin}”>

</StackPanel>

[/code]

The identifier specified along with StaticResource is the key for the desired resource. Because the object with the PhoneTitlePanelMargin key is the right data type for the Margin property, setting it this way is valid and behaves exactly the same as setting it directly:

[code]

<StackPanel Grid.Row=”0” Margin=”24,16,0,12”>

</StackPanel>

[/code]

A Hierarchy of Resource Dictionaries

All visual elements have their own resource dictionary (e.g. a Resources property), not just a page. And the StaticResource mechanism doesn’t simply look in the current page’s resource dictionary for the matching key. It starts by checking the current element’s resource dictionary, and then it checks the parent element, its parent, and so on until it reaches the root element (the frame containing the current page). After that, it checks a resource dictionary defined on the Application object.

You can see the application-wide resource dictionary in any project, initially empty, in the Visual Studio-generated App.xaml file:

[code]

<Application …>
<!– Add a style to the application-wide resource dictionary –>
<Application.Resources>
</Application.Resources>

</Application>

[/code]

This means that you can define a toplevel set of resources and override them at arbitrary points in the tree of elements (similar to data contexts). Although each individual resource dictionary requires unique keys, the same key can be used in multiple dictionaries. The one “closest” to the element referencing the resource wins.

The reason why we’ve been able to use StaticResource to reference phone theme resources such as PhoneForegroundBrush and PhoneBackgroundBrush is that these resources are automatically injected into the app when it starts. You can see the resource dictionary for each combination of theme and accent color in ThemeResources.xaml files under %ProgramFiles%Microsoft SDKsWindows Phonev7.0Design.

If you reference a resource in C#, you need to retrieve it from the exact dictionary containing it, for example:

[code]

// Get a resource from the page’s resource dictionary
this.someElement.Margin = (Thickness)this.Resources[“PhoneTitlePanelMargin”];

[/code]

Or as done in the Ruler app:

[code]

// Get a resource from the application-wide resource dictionary
this.LayoutRoot.Background =
Application.Current.Resources[“PhoneChromeBrush”] as Brush;

[/code]

C# code doesn’t have an automatic mechanism to find a resource in multiple locations, like what happens in XAML.

Styles

A style is a pretty simple entity. It collects several property values that could otherwise be set individually. It does this with a collection of setters that each names a property and its value, as with the following style from Listing 9.1:

[code]

<!– A style for text blocks that act as a label for a text box –>
<Style x:Key=”LabelStyle” TargetType=”TextBlock”>
<Setter Property=”Foreground” Value=”{StaticResource PhoneSubtleBrush}”/>
<Setter Property=”Margin” Value=”24,17,24,-5”/>
</Style>

[/code]

Visual elements have a Style property that can be directly set to an instance of a style, but the point of using a style is to define it as a resource instead. That way, you get the flexibility of sharing and overriding styles. Styles can be applied just like any other resource:

[code]

<TextBlock Text=”Carrier name” Style=”{StaticResource LabelStyle}”/>

[/code]

Notice that styles stored as resources often contain their own references to other resources. A resource can reference earlier resources from the same resource dictionary, or from a parent resource dictionary (such as the application-wide resource dictionary containing PhoneSubtleBrush in this example).

Note that style setters are for properties only. You cannot attach event handlers as part of a style.

The Code-Behind

Listing 9.2 contains the code-behind for the main page.

[code]

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
namespace WindowsPhoneApp
{
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
// Restore saved text box contents when entering this page
this.PhoneNumberTextBox.Text = Settings.PhoneNumber.Value;
this.CarrierTextBox.Text = Settings.Carrier.Value;
// Restore the time if it’s in the future, otherwise use the current time
if (Settings.CallTime.Value > DateTime.Now)
this.TimePicker.Value = Settings.CallTime.Value;
else
this.TimePicker.Value = DateTime.Now;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
// Persist contents when leaving this page for any reason
Settings.CallTime.Value = this.TimePicker.Value ?? DateTime.Now;
Settings.PhoneNumber.Value = this.PhoneNumberTextBox.Text;
Settings.Carrier.Value = this.CarrierTextBox.Text;
}
void TextBox_GotFocus(object sender, RoutedEventArgs e)
{
// Select all text so it can be cleared with one keystroke
(sender as TextBox).SelectAll();
}
void TextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
// Cycle through the text boxes
if (sender == this.PhoneNumberTextBox)
this.CarrierTextBox.Focus();
else if (sender == this.CarrierTextBox)
this.TimePicker.Focus(); // Cycle back to the beginning
e.Handled = true;
}
}
void WaitForCallButton_Click(object sender, RoutedEventArgs e)
{
// Go to the next page
this.NavigationService.Navigate(new Uri(“/IncomingCallPage.xaml”,
UriKind.Relative));
}
void TimePicker_ValueChanged(object sender, DateTimeValueChangedEventArgs e)
{
// To prevent getting clobbered on way back in
Settings.CallTime.Value = e.NewDateTime ?? DateTime.Now;
}
}
}

[/code]

Notes:

The Incoming-Call Page

The incoming-call page has two modes, shown in Figure 9.3 with ShowGridLines=”True” temporarily set on the page’s innermost grid. While waiting for the fake call to arrive, the screen is black to simulate it being off. When the call arrives, the screen mimics the incoming-call experience from the real Phone app. To help the user get used to how the app works, the “waiting mode” also shows a countdown to the call, but this can be hidden by tapping the screen. When using this app for real, the user should hide the countdown to avoid exposing the secret.

FIGURE 9.3 The two modes of the incoming-call page, with some grid lines showing to help explain the layout.

The User Interface

Listing 9.3 contains the XAML file for the incoming-call page.

LISTING 9.3 IncomingCall.xaml—The User Interface for Fake Call’s Incoming Call Page

[code]

<phone:PhoneApplicationPage
x:Class=”WindowsPhoneApp.IncomingCallPage”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
xmlns:phone=”clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone”
xmlns:local=”clr-namespace:WindowsPhoneApp”
FontFamily=”{StaticResource PhoneFontFamilyNormal}”
FontSize=”{StaticResource PhoneFontSizeNormal}”
Foreground=”{StaticResource PhoneForegroundBrush}”
SupportedOrientations=”Portrait”>
<!– Add one item to the page’s resource dictionary –>
<phone:PhoneApplicationPage.Resources>
<!– A style for the two text blocks in WaitingForCallPanel –>
<Style x:Key=”WaitingTextStyle” TargetType=”TextBlock”>
<Setter Property=”Foreground” Value=”#99FFFFFF”/>
<Setter Property=”FontFamily”
Value=”{StaticResource PhoneFontFamilySemiBold}”/>
<Setter Property=”FontSize” Value=”23”/>
</Style>
</phone:PhoneApplicationPage.Resources>
<!– A 1×1 grid holds two overlapping stack panels –>
<Grid>
<!– The initial panel that can show a countdown to the phone call –>
<StackPanel x:Name=”WaitingForCallPanel” Background=”Black”>
<TextBlock x:Name=”CountdownTextBlock” Margin=”11,120,0,0”
Style=”{StaticResource WaitingTextStyle}”/>
<TextBlock x:Name=”TapToHideTextBlock” Margin=”11,0,0,0”
Text=”(tap screen to hide)”
Style=”{StaticResource WaitingTextStyle}”/>
</StackPanel>
<!– The fake “incoming call” user interface –>
<StackPanel x:Name=”IncomingCallPanel” Visibility=”Collapsed”
Background=”{StaticResource PhoneChromeBrush}”>
<!– These two text blocks form the fake status bar –>
<TextBlock x:Name=”CurrentTimeTextBlock”
Style=”{StaticResource StatusBarTextStyle}”/>
<TextBlock x:Name=”CarrierTextBlock”
Style=”{StaticResource StatusBarTextStyle}”
Foreground=”{StaticResource PhoneSubtleBrush}”/>
<Grid Margin=”12,1,12,0” Height=”566”>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height=”Auto”/>
<RowDefinition Height=”Auto”/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<!– “INCOMING CALL” –>
<TextBlock Grid.ColumnSpan=”2” Text=”INCOMING CALL” Margin=”11,0,0,-10”
VerticalAlignment=”Bottom” FontSize=”23”
FontFamily=”{StaticResource PhoneFontFamilySemiBold}”
Foreground=”{StaticResource PhoneAccentBrush}”/>
<!– The phone number –>
<TextBlock x:Name=”PhoneNumberTextBlock” Grid.Row=”1” Grid.ColumnSpan=”2”
Margin=”6,22,0,51” TextWrapping=”Wrap” FontSize=”85”
LineHeight=”91” LineStackingStrategy=”BlockLineHeight”
FontFamily=”{StaticResource PhoneFontFamilySemiLight}” />
<!– The answer/ignore buttons –>
<Button Grid.Row=”2” Content=”answer” Click=”AnswerButton_Click”
local:Tilt.IsEnabled=”True”/>
<Button Grid.Column=”1” Grid.Row=”2” Content=”ignore”
Click=”IgnoreButton_Click” local:Tilt.IsEnabled=”True”/>
</Grid>
</StackPanel>
</Grid>
</phone:PhoneApplicationPage>

[/code]

Notes:

FIGURE 9.4 The impact of giving a wrapping text block an explicit line height.
FIGURE 9.5 The text grows upward while the buttons remain in a fixed position.

The Code-Behind

Listing 9.4 contains the code-behind for the incoming-call page.

LISTING 9.4 IncomingCall.xaml.cs—The Code-Behind for Fake Call’s Incoming Call Page

[code]

using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Windows.Threading;
using Microsoft.Devices;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
namespace WindowsPhoneApp
{
public partial class IncomingCallPage : PhoneApplicationPage
{
// A timer that ticks once per second to keep track of the time
DispatcherTimer timer = new DispatcherTimer {
Interval = TimeSpan.FromSeconds(1)
};
// A variable-interval timer that performs the call vibration pattern
DispatcherTimer vibrationTimer = new DispatcherTimer();
// Bookkeeping for the vibration pattern used to simulate ringing
bool isRinging;
int vibrationStep;
public IncomingCallPage()
{
InitializeComponent();
this.timer.Tick += Timer_Tick;
this.vibrationTimer.Tick += VibrationTimer_Tick;
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
if (this.WaitingForCallPanel.Visibility == Visibility.Visible)
{
// Hide the contents of WaitingForCallPanel when the screen is tapped
this.CountdownTextBlock.Visibility = Visibility.Collapsed;
this.TapToHideTextBlock.Visibility = Visibility.Collapsed;
}
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
// Respect the current settings
this.CarrierTextBlock.Text = Settings.Carrier.Value;
this.PhoneNumberTextBlock.Text = Settings.PhoneNumber.Value;
// Start the main timer
this.timer.Start();
Timer_Tick(null, null); // Force initial update
// While on this page, don’t allow the screen to auto-lock
PhoneApplicationService.Current.UserIdleDetectionMode =
IdleDetectionMode.Disabled;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
// Stop the main timer
this.timer.Stop();
// Stop ringing (if ringing)
StopRinging();
// Restore the ability for the screen to auto-lock when on other pages
PhoneApplicationService.Current.UserIdleDetectionMode =
IdleDetectionMode.Enabled;
}
void StartRinging()
{
// Show IncomingCallPanel and start the vibration pattern
isRinging = true;
this.WaitingForCallPanel.Visibility = Visibility.Collapsed;
this.IncomingCallPanel.Visibility = Visibility.Visible;
this.vibrationStep = 0;
this.vibrationTimer.Start();
}
void StopRinging()
{
// Hide IncomingCallPanel, stop the vibration, and set the next call time
// to two minutes from now
isRinging = false;
this.WaitingForCallPanel.Visibility = Visibility.Visible;
this.IncomingCallPanel.Visibility = Visibility.Collapsed;
this.vibrationTimer.Stop();
Settings.CallTime.Value = DateTime.Now + TimeSpan.FromMinutes(2);
Timer_Tick(null, null); // Force an update now
}
void Timer_Tick(object sender, EventArgs e)
{
// Show the current time on the fake status bar
this.CurrentTimeTextBlock.Text = DateTime.Now.ToString(“h:mm”);
TimeSpan delta = Settings.CallTime.Value – DateTime.Now;
if (delta > TimeSpan.Zero)
{
// It’s not time to ring yet. Update the countdown in case it is visible.
this.CountdownTextBlock.Text = “COUNTDOWN: “ + (int)delta.TotalHours + “:”
+ delta.Minutes.ToString(“00”) + “:”
+ Math.Ceiling(delta.Seconds).ToString(“00”);
}
else if (!this.isRinging)
{
// It’s time to ring
StartRinging();
}
}
void AnswerButton_Click(object sender, RoutedEventArgs e)
{
// Go to the next page
this.NavigationService.Navigate(new Uri(“/CallInProgressPage.xaml”,
UriKind.Relative));
}
void IgnoreButton_Click(object sender, RoutedEventArgs e)
{
StopRinging();
}
void VibrationTimer_Tick(object sender, EventArgs e)
{
// Make a short-long-short-long pattern of vibration
switch (this.vibrationStep % 4) // Cycle from 0 – 3
{
case 0:
case 2:
VibrateController.Default.Start(TimeSpan.FromSeconds(.1)); // short
// Leave space between this short and the next long
this.vibrationTimer.Interval = TimeSpan.FromSeconds(.4);
break;
case 1:
VibrateController.Default.Start(TimeSpan.FromSeconds(.4)); // long
// Leave more space between this long and the next short
this.vibrationTimer.Interval = TimeSpan.FromSeconds(.8);
break;
case 3:
VibrateController.Default.Start(TimeSpan.FromSeconds(.4)); // long
// Leave even more space after every other long
this.vibrationTimer.Interval = TimeSpan.FromSeconds(2.1);
break;
}
this.vibrationStep++;
// Stop ringing after 20 seconds (6 full cycles of the 4-part pattern)
if (this.vibrationStep == 24)
StopRinging();
}
}
}

[/code]

Notes:

The Call-In-Progress Page

The final page—the call-in-progress page—is pictured in Figure 9.6 with ShowGridLines=”True” marked on its second grid.

 

FIGURE 9.6 The call-in-progress page, with some grid lines showing to help explain the layout.

 The User Interface

Listing 9.5 contains this page’s XAML file.

LISTING 9.5 CallInProgress.xaml—The User Interface for Fake Call’s Call-In-Progress Page

[code]

<phone:PhoneApplicationPage
x:Class=”WindowsPhoneApp.CallInProgressPage”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
xmlns:phone=”clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone”
xmlns:local=”clr-namespace:WindowsPhoneApp”
xmlns:sys=”clr-namespace:System;assembly=mscorlib”
FontFamily=”{StaticResource PhoneFontFamilyNormal}”
FontSize=”{StaticResource PhoneFontSizeNormal}”
Foreground=”{StaticResource PhoneForegroundBrush}”
SupportedOrientations=”Portrait”>
<!– Add two items to the page’s resource dictionary –>
<phone:PhoneApplicationPage.Resources>
<Thickness x:Key=”ButtonMargin”>0,41,0,12</Thickness>
<sys:Int32 x:Key=”SmallButtonWidth”>88</sys:Int32>
</phone:PhoneApplicationPage.Resources>
<StackPanel Background=”{StaticResource PhoneChromeBrush}”
VerticalAlignment=”Top”>
<Grid>
<!– The fake signal-strength bars for the fake status bar –>
<Canvas>
<!– Add two styles to this canvas’s resource dictionary –>
<Canvas.Resources>
<Style x:Key=”BarOnStyle” TargetType=”Line”>
<Setter Property=”Stroke”
Value=”{StaticResource PhoneForegroundBrush}”/>
<Setter Property=”StrokeThickness” Value=”5”/>
<Setter Property=”Y2” Value=”26”/>
</Style>
<Style x:Key=”BarOffStyle” BasedOn=”{StaticResource BarOnStyle}”
TargetType=”Line”>
<Setter Property=”Stroke” Value=”{StaticResource PhoneSubtleBrush}”/>
<Setter Property=”Opacity” Value=”.3”/>
</Style>
</Canvas.Resources>
<Line Style=”{StaticResource BarOnStyle}”
X1=”16” X2=”16” Y1=”22”/>
<Line Style=”{StaticResource BarOnStyle}”
X1=”22” X2=”22” Y1=”18”/>
<Line Style=”{StaticResource BarOffStyle}”
X1=”28” X2=”28” Y1=”15”/>
<Line Style=”{StaticResource BarOffStyle}”
X1=”34” X2=”34” Y1=”11”/>
<Line Style=”{StaticResource BarOffStyle}”
X1=”40” X2=”40” Y1=”7”/>
</Canvas>
<!– The current time for the fake status bar–>
<TextBlock x:Name=”CurrentTimeTextBlock”
Style=”{StaticResource StatusBarTextStyle}”/>
</Grid>
<!– The carrier for the fake status bar–>
<TextBlock x:Name=”CarrierTextBlock”
Style=”{StaticResource StatusBarTextStyle}”
Foreground=”{StaticResource PhoneSubtleBrush}”/>
<Grid Margin=”12,1,12,0”>
<Grid.RowDefinitions>
<RowDefinition Height=”Auto”/>
<RowDefinition Height=”Auto”/>
<RowDefinition Height=”Auto”/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width=”Auto”/>
<ColumnDefinition Width=”Auto”/>
</Grid.ColumnDefinitions>
<TextBlock x:Name=”CallDurationTextBlock” Grid.ColumnSpan=”3” FontSize=”21”
Margin=”12,20,0,0” Foreground=”{StaticResource PhoneAccentBrush}”/>
<TextBlock x:Name=”PhoneNumberTextBlock” Grid.Row=”1” Grid.ColumnSpan=”3”
Margin=”6,-5,0,28” TextWrapping=”Wrap” FontSize=”68”
FontFamily=”{StaticResource PhoneFontFamilySemiLight}” />
<!– The “end call” button –>
<Button Grid.Row=”2” Content=”end call” Click=”EndCallButton_Click”
Margin=”{StaticResource ButtonMargin}” local:Tilt.IsEnabled=”True”
Background=”{StaticResource PhoneAccentBrush}”/>
<!– The fake keypad button –>
<Button Grid.Row=”2” Grid.Column=”1” Margin=”{StaticResource ButtonMargin}”
Width=”{StaticResource SmallButtonWidth}” local:Tilt.IsEnabled=”True”>
<Canvas Width=”16” Height=”18”>
<!– Add a style to this canvas’s resource dictionary –>
<Canvas.Resources>
<Style x:Key=”SquareStyle” TargetType=”Rectangle”>
<Setter Property=”Width” Value=”4”/>
<Setter Property=”Height” Value=”4”/>
<Setter Property=”Fill”
Value=”{StaticResource PhoneForegroundBrush}”/>
</Style>
</Canvas.Resources>
<Rectangle Style=”{StaticResource SquareStyle}”/>
<Rectangle Canvas.Left=”6” Style=”{StaticResource SquareStyle}”/>
<Rectangle Canvas.Left=”12” Style=”{StaticResource SquareStyle}”/>
<Rectangle Canvas.Top=”6” Style=”{StaticResource SquareStyle}”/>
<Rectangle Canvas.Left=”6” Canvas.Top=”6”
Style=”{StaticResource SquareStyle}”/>
<Rectangle Canvas.Left=”12” Canvas.Top=”6”
Style=”{StaticResource SquareStyle}”/>
<Rectangle Canvas.Top=”12” Style=”{StaticResource SquareStyle}”/>
<Rectangle Canvas.Left=”6” Canvas.Top=”12”
Style=”{StaticResource SquareStyle}”/>
<Rectangle Canvas.Left=”12” Canvas.Top=”12”
Style=”{StaticResource SquareStyle}”/>
<Rectangle Canvas.Left=”6” Canvas.Top=”18”
Style=”{StaticResource SquareStyle}”/>
</Canvas>
</Button>
<!– The fake double-arrow button –>
<Button Width=”{StaticResource SmallButtonWidth}” Grid.Row=”2”
Grid.Column=”2” Margin=”{StaticResource ButtonMargin}”
local:Tilt.IsEnabled=”True”>
<Path Fill=”{StaticResource PhoneForegroundBrush}”
Data=”M0,2 14,2 7,11z M0,13 14,13 7,22” />
</Button>
</Grid>
</StackPanel>
</phone:PhoneApplicationPage>

[/code]

Notes:

FIGURE 9.7 The buttons get pushed downward to make room for long text.

The Code-Behind

Listing 9.6 contains the code-behind for this page.

LISTING 9.6 CallInProgress.xaml.cs—The Code-Behind for Fake Call’s Call-In-Progress Page

[code]

using System;
using System.Windows;
using System.Windows.Navigation;
using System.Windows.Threading;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
namespace WindowsPhoneApp
{
public partial class CallInProgressPage : PhoneApplicationPage
{
// A timer that ticks once per second to keep track of the time
DispatcherTimer timer = new DispatcherTimer {
Interval = TimeSpan.FromSeconds(1) };
TimeSpan callDuration;
public CallInProgressPage()
{
InitializeComponent();
this.timer.Tick += Timer_Tick;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
// Respect the current settings
this.CarrierTextBlock.Text = Settings.Carrier.Value;
this.PhoneNumberTextBlock.Text = Settings.PhoneNumber.Value;
// Start at -1 seconds because Timer_Tick is about to increase it by 1
this.callDuration = TimeSpan.Zero – TimeSpan.FromSeconds(1);
// Start the main timer
this.timer.Start();
Timer_Tick(null, null); // Force an update now
// While on this page, don’t allow the screen to auto-lock
PhoneApplicationService.Current.UserIdleDetectionMode =
IdleDetectionMode.Disabled;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
// Stop the main timer
this.timer.Stop();
// Set the next call time to two minutes from now
Settings.CallTime.Value = DateTime.Now + TimeSpan.FromMinutes(2);
// Restore the ability for the screen to auto-lock when on other pages
PhoneApplicationService.Current.UserIdleDetectionMode =
IdleDetectionMode.Enabled;
}
void Timer_Tick(object sender, EventArgs e)
{
// Show the current time on the fake status bar
this.CurrentTimeTextBlock.Text = DateTime.Now.ToString(“h:mm”);
// Update the call duration display
this.callDuration = this.callDuration.Add(TimeSpan.FromSeconds(1));
this.CallDurationTextBlock.Text = (int)this.callDuration.TotalMinutes +
“:” + this.callDuration.Seconds.ToString(“00”);
}
void EndCallButton_Click(object sender, RoutedEventArgs e)
{
// Go back to the incoming call page, which will wait for the next call
if (this.NavigationService.CanGoBack)
this.NavigationService.GoBack();
}
}
}

[/code]

The code-behind for this page is similar to the code-behind for the previous page, just a bit simpler. Ideally, the app would just exit when the user taps the “end call” button, but there’s no good way to accomplish this. Therefore, after the user taps “end call,” they can either press the Power button to lock their phone or the Start button to leave this app—if they don’t want to be fake-called again in 2 minutes.

Exiting an App Programmatically

To make the app easier to quickly exit, you could merge all of Fake Call’s functionality onto one page to avoid filling the back stack. However, this would make the code messier, and the user would still need to press the hardware Back button to exit the app.

Throwing an unhandled exception would force the app to exit, but this has two problems. If you do this, settings won’t be properly persisted to disk (because this is internally done during a graceful app shutdown). Also, such behavior would not get past the marketplace certification process. So don’t ever attempt to force an app to exit this way!

Another approach would be to call XNA’s Game.Exit method from the Microsoft.Xna. Framework.Game assembly.However, calling anything from this assembly will cause your app to fail marketplace certification.You might be able to get away with using .NET reflection to call Game.Exit in a way that the certification process doesn’t detect, but I wouldn’t recommend it.

The Finished Product

Exit mobile version