Got app running on phone
Separated score view into helper functions

Change-Id: I7c96022ff4b9954d57d3bd2987872d756f0852cb
diff --git a/go/src/hearts/AndroidManifest.xml b/go/src/hearts/AndroidManifest.xml
new file mode 100644
index 0000000..1e434ff
--- /dev/null
+++ b/go/src/hearts/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright 2015 The Go Authors. All rights reserved.
+Use of this source code is governed by a BSD-style
+license that can be found in the LICENSE file.
+-->
+<manifest
+	xmlns:android="http://schemas.android.com/apk/res/android"
+	package="io.v.go.examples.aaavolley"
+	android:versionCode="1"
+	android:versionName="1.0">
+
+	<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="19" />
+
+	<!-- http://developer.android.com/guide/topics/manifest/manifest-intro.html#perms -->
+  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+  <uses-permission android:name="android.permission.INTERNET"/>
+  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+  <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    
+	<application android:label="aaavolley" android:debuggable="true">
+
+	<activity android:name="org.golang.app.GoNativeActivity"
+		android:label="aaavolley"
+		android:configChanges="orientation|keyboardHidden">
+		<meta-data android:name="android.app.lib_name" android:value="network" />
+		<intent-filter>
+			<action android:name="android.intent.action.MAIN" />
+			<category android:name="android.intent.category.LAUNCHER" />
+		</intent-filter>
+	</activity>
+	</application>
+</manifest>
\ No newline at end of file
diff --git a/go/src/hearts/img/texture/texture.go b/go/src/hearts/img/texture/texture.go
index 9da057d..78763c0 100644
--- a/go/src/hearts/img/texture/texture.go
+++ b/go/src/hearts/img/texture/texture.go
@@ -218,6 +218,10 @@
 	return s
 }
 
+func RemoveImg(s *staticimg.StaticImg, u *uistate.UIState) {
+	u.Eng.Unregister(s.GetNode())
+}
+
 // Loads all images for the app
 func LoadTextures(eng sprite.Engine) map[string]sprite.SubTex {
 	allTexs := make(map[string]sprite.SubTex)
diff --git a/go/src/hearts/img/view/view.go b/go/src/hearts/img/view/view.go
index 4c45f81..0155c51 100644
--- a/go/src/hearts/img/view/view.go
+++ b/go/src/hearts/img/view/view.go
@@ -237,7 +237,7 @@
 func LoadPassOrTakeOrPlay(u *uistate.UIState) {
 	p := u.CurTable.GetPlayers()[u.CurPlayerIndex]
 	if p.GetDoneTaking() || u.CurTable.GetDir() == direction.None {
-		LoadPlayView(u)
+		LoadPlayView("", u)
 	} else if p.GetDonePassing() {
 		LoadTakeView(u)
 	} else {
@@ -251,76 +251,9 @@
 	resetImgs(u)
 	resetScene(u)
 	addHeader(u)
-	top := u.CardDim.Y
-	scaler := float32(4)
-	maxWidth := u.WindowSize.X / 4
-	totalScores := make([]int, 0)
-	for _, p := range u.CurTable.GetPlayers() {
-		totalScores = append(totalScores, p.GetScore())
-	}
-	maxRoundScore := maxInt(roundScores)
-	maxTotalScore := maxInt(totalScores)
-	// adding score text
-	center := coords.MakeVec(u.WindowSize.X/4, top)
-	u.BackgroundImgs = append(u.BackgroundImgs,
-		texture.MakeStringImgCenterAlign("Score:", "", "", true, center, scaler, maxWidth, u)...)
-	// adding game text
-	center = coords.MakeVec(u.WindowSize.X/2, top)
-	u.BackgroundImgs = append(u.BackgroundImgs,
-		texture.MakeStringImgCenterAlign("Round", "", "", true, center, scaler, maxWidth, u)...)
-	// adding total text
-	center = coords.MakeVec(3*u.WindowSize.X/4, top)
-	u.BackgroundImgs = append(u.BackgroundImgs,
-		texture.MakeStringImgCenterAlign("Total", "", "", true, center, scaler, maxWidth, u)...)
-	// adding player info
-	rowHeight := u.WindowSize.Y / 5
-	for i, p := range u.CurTable.GetPlayers() {
-		var color string
-		// blue divider
-		dividerImage := u.Texs["blue.png"]
-		dividerDim := coords.MakeVec(u.WindowSize.X, u.Padding/2)
-		dividerPos := coords.MakeVec(0, top+(float32(i)+.5)*rowHeight)
-		u.BackgroundImgs = append(u.BackgroundImgs,
-			texture.MakeImgWithoutAlt(dividerImage, dividerPos, dividerDim, u.Eng, u.Scene))
-		// player icon
-		playerIconImage := p.GetImage()
-		playerIconDim := coords.MakeVec(rowHeight/2, rowHeight/2)
-		playerIconPos := coords.MakeVec(u.WindowSize.X/4-playerIconDim.X/2, top+(float32(i)+.5)*rowHeight+3*u.Padding)
-		u.BackgroundImgs = append(u.BackgroundImgs,
-			texture.MakeImgWithoutAlt(playerIconImage, playerIconPos, playerIconDim, u.Eng, u.Scene))
-		// player name
-		name := p.GetName()
-		center = coords.MakeVec(playerIconPos.X+playerIconDim.X/2, playerIconPos.Y+playerIconDim.Y)
-		u.BackgroundImgs = append(u.BackgroundImgs,
-			texture.MakeStringImgCenterAlign(name, "", "", true, center, scaler, maxWidth, u)...)
-		// player round score
-		roundScore := roundScores[i]
-		if roundScore == maxRoundScore {
-			color = "Red"
-		} else {
-			color = ""
-		}
-		center = coords.MakeVec(u.WindowSize.X/2, playerIconPos.Y+playerIconDim.Y/2)
-		u.BackgroundImgs = append(u.BackgroundImgs,
-			texture.MakeStringImgCenterAlign(strconv.Itoa(roundScore), color, color, true, center, scaler, maxWidth, u)...)
-		// player total score
-		totalScore := p.GetScore()
-		if totalScore == maxTotalScore {
-			color = "Red"
-		} else {
-			color = ""
-		}
-		center = coords.MakeVec(3*u.WindowSize.X/4, playerIconPos.Y+playerIconDim.Y/2)
-		u.BackgroundImgs = append(u.BackgroundImgs,
-			texture.MakeStringImgCenterAlign(strconv.Itoa(totalScore), color, color, true, center, scaler, maxWidth, u)...)
-	}
-	// adding play button to move to next round
-	pressedImg := u.Texs["playPressed.png"]
-	unpressedImg := u.Texs["playUnpressed.png"]
-	buttonDim := coords.MakeVec(2*u.CardDim.X, u.CardDim.Y)
-	buttonPos := coords.MakeVec((u.WindowSize.X-u.CardDim.X)/2, u.WindowSize.Y-u.CardDim.Y-u.BottomPadding)
-	u.Buttons = append(u.Buttons,
-		texture.MakeImgWithAlt(unpressedImg, pressedImg, buttonPos, buttonDim, true, u.Eng, u.Scene))
+	addScoreViewHeaderText(u)
+	addPlayerScores(roundScores, u)
+	addScoreButton(u)
 }
 
 // Pass View: Shows player's hand and allows them to pass cards
@@ -354,19 +287,31 @@
 }
 
 // Play View: Shows player's hand and allows them to play cards
-func LoadPlayView(u *uistate.UIState) {
+func LoadPlayView(err string, u *uistate.UIState) {
 	u.CurView = uistate.Play
-	resetImgs(u)
-	resetScene(u)
-	addPlaySlot(u)
-	addHand(u)
-	addPlayHeader(u)
-	if u.Debug {
-		addDebugBar(u)
-	}
-	// animate in play slot if relevant
-	if u.CurTable.WhoseTurn() == u.CurPlayerIndex && u.CurTable.AllDonePassing() {
-		reposition.AnimateInPlay(u)
+	if err == "" {
+		resetImgs(u)
+		resetScene(u)
+		addPlaySlot(u)
+		addHand(u)
+		addPlayHeader(err, u)
+		if u.Debug {
+			addDebugBar(u)
+		}
+		// animate in play slot if relevant
+		if u.CurTable.WhoseTurn() == u.CurPlayerIndex && u.CurTable.AllDonePassing() {
+			reposition.AnimateInPlay(u)
+		}
+	} else {
+		// remove text and replace with err
+		var emptyTex sprite.SubTex
+		for i := u.NumSuits; i < len(u.BackgroundImgs); i++ {
+			u.Eng.SetSubTex(u.BackgroundImgs[i].GetNode(), emptyTex)
+		}
+		u.BackgroundImgs = u.BackgroundImgs[:u.NumSuits]
+		u.Eng.SetSubTex(u.Buttons[0].GetNode(), emptyTex)
+		u.Buttons = make([]*staticimg.StaticImg, 0)
+		addPlayHeader(err, u)
 	}
 }
 
@@ -379,7 +324,7 @@
 		texture.MakeImgWithoutAlt(headerImage, headerPos, headerDimensions, u.Eng, u.Scene))
 }
 
-func addPlayHeader(u *uistate.UIState) {
+func addPlayHeader(err string, u *uistate.UIState) {
 	// adding blue banner
 	headerImage := u.Texs["Rectangle-DBlue.png"]
 	headerPos := coords.MakeVec(0, 0)
@@ -394,21 +339,25 @@
 		texture.MakeImgWithoutAlt(pullTabImage, pullTabPos, pullTabDim, u.Eng, u.Scene))
 	// adding text
 	var turnText string
-	playerTurnNum := u.CurTable.WhoseTurn()
-	if playerTurnNum == -1 || !u.CurTable.AllDonePassing() {
-		turnText = "Waiting for other players"
-	} else if playerTurnNum == u.CurPlayerIndex {
-		turnText = "Your turn"
+	if err != "" {
+		turnText = err
 	} else {
-		name := u.CurTable.GetPlayers()[playerTurnNum].GetName()
-		turnText = name + "'s turn"
+		playerTurnNum := u.CurTable.WhoseTurn()
+		if playerTurnNum == -1 || !u.CurTable.AllDonePassing() {
+			turnText = "Waiting for other players"
+		} else if playerTurnNum == u.CurPlayerIndex {
+			turnText = "Your turn"
+		} else {
+			name := u.CurTable.GetPlayers()[playerTurnNum].GetName()
+			turnText = name + "'s turn"
+		}
 	}
 	color := "DBlue"
 	scaler := float32(4)
 	center := coords.MakeVec(u.WindowSize.X/2, 20)
 	maxWidth := u.WindowSize.X - pullTabDim.X/2
-	nameImgs := texture.MakeStringImgCenterAlign(turnText, color, color, true, center, scaler, maxWidth, u)
-	u.BackgroundImgs = append(u.BackgroundImgs, nameImgs...)
+	u.BackgroundImgs = append(u.BackgroundImgs,
+		texture.MakeStringImgCenterAlign(turnText, color, color, true, center, scaler, maxWidth, u)...)
 }
 
 func addPlaySlot(u *uistate.UIState) {
@@ -635,6 +584,85 @@
 	}
 }
 
+func addScoreViewHeaderText(u *uistate.UIState) {
+	top := u.CardDim.Y
+	scaler := float32(4)
+	maxWidth := u.WindowSize.X / 4
+	// adding score text
+	scoreCenter := coords.MakeVec(u.WindowSize.X/4, top)
+	u.BackgroundImgs = append(u.BackgroundImgs,
+		texture.MakeStringImgCenterAlign("Score:", "", "", true, scoreCenter, scaler, maxWidth, u)...)
+	// adding game text
+	gameCenter := coords.MakeVec(u.WindowSize.X/2, top)
+	u.BackgroundImgs = append(u.BackgroundImgs,
+		texture.MakeStringImgCenterAlign("Round", "", "", true, gameCenter, scaler, maxWidth, u)...)
+	// adding total text
+	totalCenter := coords.MakeVec(3*u.WindowSize.X/4, top)
+	u.BackgroundImgs = append(u.BackgroundImgs,
+		texture.MakeStringImgCenterAlign("Total", "", "", true, totalCenter, scaler, maxWidth, u)...)
+}
+
+func addPlayerScores(roundScores []int, u *uistate.UIState) {
+	totalScores := make([]int, 0)
+	for _, p := range u.CurTable.GetPlayers() {
+		totalScores = append(totalScores, p.GetScore())
+	}
+	maxRoundScore := maxInt(roundScores)
+	maxTotalScore := maxInt(totalScores)
+	top := u.CardDim.Y
+	scaler := float32(4)
+	maxWidth := u.WindowSize.X / 4
+	rowHeight := u.WindowSize.Y / 6
+	for i, p := range u.CurTable.GetPlayers() {
+		var color string
+		// blue divider
+		dividerImage := u.Texs["blue.png"]
+		dividerDim := coords.MakeVec(u.WindowSize.X, u.Padding/2)
+		dividerPos := coords.MakeVec(0, top+(float32(i)+.5)*rowHeight)
+		u.BackgroundImgs = append(u.BackgroundImgs,
+			texture.MakeImgWithoutAlt(dividerImage, dividerPos, dividerDim, u.Eng, u.Scene))
+		// player icon
+		playerIconImage := p.GetImage()
+		playerIconDim := coords.MakeVec(rowHeight/2, rowHeight/2)
+		playerIconPos := coords.MakeVec(u.WindowSize.X/4-playerIconDim.X/2, top+(float32(i)+.5)*rowHeight+2*u.Padding)
+		u.BackgroundImgs = append(u.BackgroundImgs,
+			texture.MakeImgWithoutAlt(playerIconImage, playerIconPos, playerIconDim, u.Eng, u.Scene))
+		// player name
+		name := p.GetName()
+		nameCenter := coords.MakeVec(playerIconPos.X+playerIconDim.X/2, playerIconPos.Y+playerIconDim.Y)
+		u.BackgroundImgs = append(u.BackgroundImgs,
+			texture.MakeStringImgCenterAlign(name, "", "", true, nameCenter, scaler, maxWidth, u)...)
+		// player round score
+		roundScore := roundScores[i]
+		if roundScore == maxRoundScore {
+			color = "Red"
+		} else {
+			color = ""
+		}
+		roundCenter := coords.MakeVec(u.WindowSize.X/2, playerIconPos.Y+playerIconDim.Y/2)
+		u.BackgroundImgs = append(u.BackgroundImgs,
+			texture.MakeStringImgCenterAlign(strconv.Itoa(roundScore), color, color, true, roundCenter, scaler, maxWidth, u)...)
+		// player total score
+		totalScore := p.GetScore()
+		if totalScore == maxTotalScore {
+			color = "Red"
+		} else {
+			color = ""
+		}
+		totalCenter := coords.MakeVec(3*u.WindowSize.X/4, playerIconPos.Y+playerIconDim.Y/2)
+		u.BackgroundImgs = append(u.BackgroundImgs,
+			texture.MakeStringImgCenterAlign(strconv.Itoa(totalScore), color, color, true, totalCenter, scaler, maxWidth, u)...)
+	}
+}
+
+func addScoreButton(u *uistate.UIState) {
+	buttonImg := u.Texs["playUnpressed.png"]
+	buttonDim := coords.MakeVec(2*u.CardDim.X, u.CardDim.Y)
+	buttonPos := coords.MakeVec((u.WindowSize.X-u.CardDim.X)/2, u.WindowSize.Y-u.CardDim.Y-u.BottomPadding)
+	u.Buttons = append(u.Buttons,
+		texture.MakeImgWithoutAlt(buttonImg, buttonPos, buttonDim, u.Eng, u.Scene))
+}
+
 func resetImgs(u *uistate.UIState) {
 	u.Cards = make([]*card.Card, 0)
 	u.TableCards = make([]*card.Card, 0)
diff --git a/go/src/hearts/logic/table/table.go b/go/src/hearts/logic/table/table.go
index ae70f94..073d2b4 100644
--- a/go/src/hearts/logic/table/table.go
+++ b/go/src/hearts/logic/table/table.go
@@ -145,34 +145,44 @@
 	return t.WhoseTurn() == playerIndex
 }
 
-// Given a card and the index of its player, returns true if this move was valid based on game logic
-func (t *Table) ValidPlayLogic(c *card.Card, playerIndex int) bool {
+// Given a card and the index of its player, returns "" if this move was valid based on game logic
+// Otherwise returns a string explaining the error
+func (t *Table) ValidPlayLogic(c *card.Card, playerIndex int) string {
+	validPlay := ""
 	player := t.players[playerIndex]
 	if t.firstPlayer == playerIndex {
 		if !t.firstTrick {
 			if c.GetSuit() != card.Heart || t.heartsBroken {
-				return true
+				return validPlay
 			} else {
 				if player.HasOnlyHearts() {
-					return true
+					return validPlay
+				} else {
+					return "Hearts have not been broken"
 				}
 			}
 		} else if c.GetSuit() == card.Club && c.GetFace() == card.Two {
-			return true
+			return validPlay
+		} else {
+			return "Must open with the Two of Clubs"
 		}
 	} else {
 		firstPlayedSuit := t.trick[t.firstPlayer].GetSuit()
 		if c.GetSuit() == firstPlayedSuit || !player.HasSuit(firstPlayedSuit) {
 			if !t.firstTrick {
-				return true
+				return validPlay
 			} else if !c.WorthPoints() {
-				return true
+				return validPlay
 			} else if player.HasAllPoints() {
-				return true
+				return validPlay
+			} else {
+				return "Point cards not allowed in the first round"
 			}
+		} else {
+			return "Must follow suit"
 		}
 	}
-	return false
+	return "Invalid play"
 }
 
 // Returns true if all players have their initial dealt hands
diff --git a/go/src/hearts/main.go b/go/src/hearts/main.go
index c4c8756..a8da7ff 100644
--- a/go/src/hearts/main.go
+++ b/go/src/hearts/main.go
@@ -7,6 +7,7 @@
 package main
 
 import (
+	"flag"
 	"time"
 
 	"v.io/v23"
@@ -14,6 +15,7 @@
 	"v.io/v23/security"
 	"v.io/v23/security/access"
 	"v.io/v23/syncbase"
+	"v.io/x/lib/vlog"
 	"v.io/x/ref/lib/signals"
 
 	"hearts/img/resize"
@@ -78,6 +80,9 @@
 }
 
 func onStart(glctx gl.Context, u *uistate.UIState) {
+	vlog.Log.Configure(vlog.OverridePriorConfiguration(true), vlog.LogToStderr(true))
+	vlog.Log.Configure(vlog.OverridePriorConfiguration(true), vlog.Level(0))
+
 	sgName := "users/emshack@google.com/croupier/syncbase/%%sync/croupiersync"
 	contextChan := make(chan *context.T)
 	serviceChan := make(chan syncbase.Service)
@@ -123,6 +128,7 @@
 }
 
 func makeServerClient(contextChan chan *context.T, serviceChan chan syncbase.Service) {
+	flag.Set("v23.credentials", "/sdcard/credentials")
 	context, shutdown := v23.Init()
 	contextChan <- context
 	serviceChan <- client.GetService()
diff --git a/go/src/hearts/syncbase/watch/watch.go b/go/src/hearts/syncbase/watch/watch.go
index c1e99ff..df303ce 100644
--- a/go/src/hearts/syncbase/watch/watch.go
+++ b/go/src/hearts/syncbase/watch/watch.go
@@ -94,7 +94,7 @@
 	} else if u.CurView == uistate.Take && u.CurPlayerIndex == receivingPlayer {
 		view.LoadTakeView(u)
 	} else if u.CurView == uistate.Play && u.CurTable.AllDonePassing() {
-		view.LoadPlayView(u)
+		view.LoadPlayView("", u)
 	}
 }
 
@@ -114,7 +114,7 @@
 		u.CurTable.SetFirstPlayer(p.GetPlayerIndex())
 		// UI
 		if u.CurView == uistate.Play && u.CurPlayerIndex != playerInt {
-			view.LoadPlayView(u)
+			view.LoadPlayView("", u)
 		}
 	}
 	// UI
@@ -175,7 +175,7 @@
 		if roundOver {
 			view.LoadScoreView(roundScores, winners, u)
 		} else if u.CurPlayerIndex != playerInt {
-			view.LoadPlayView(u)
+			view.LoadPlayView("", u)
 		}
 	}
 	// logic
diff --git a/go/src/hearts/touchhandler/touchhandler.go b/go/src/hearts/touchhandler/touchhandler.go
index 5edd64b..768b5c6 100644
--- a/go/src/hearts/touchhandler/touchhandler.go
+++ b/go/src/hearts/touchhandler/touchhandler.go
@@ -246,7 +246,7 @@
 				if !success {
 					fmt.Println("Invalid take")
 				} else {
-					view.LoadPlayView(u)
+					view.LoadPlayView("", u)
 				}
 			}()
 		}
@@ -287,13 +287,12 @@
 		} else {
 			ch := make(chan bool)
 			err := playCard(ch, u.CurPlayerIndex, u)
+			if err != "" {
+				view.LoadPlayView(err, u)
+			}
 			go func() {
 				<-ch
-				if err != "" {
-					fmt.Println(err)
-				} else {
-					view.LoadPlayView(u)
-				}
+				view.LoadPlayView("", u)
 			}()
 		}
 	}
@@ -391,16 +390,16 @@
 		// -the play is in the right order
 		// -the play is valid given game logic
 		if u.CurTable.GetPlayers()[playerId].GetDonePlaying() {
-			return "Invalid play: The current player has already played a card in this trick"
+			return "You have already played a card in this trick"
 		}
 		if !u.CurTable.AllDonePassing() {
-			return "Invalid play: Not all players have passed their cards"
+			return "Not all players have passed their cards"
 		}
 		if !u.CurTable.ValidPlayOrder(playerId) {
-			return "Invalid play: It is not the current player's turn"
+			return "It is not your turn"
 		}
-		if !u.CurTable.ValidPlayLogic(c, playerId) {
-			return "Invalid play: This card does not follow game logic"
+		if err := u.CurTable.ValidPlayLogic(c, playerId); err != "" {
+			return err
 		}
 		u.DropTargets[0].SetCardHere(nil)
 		success := gamelog.LogPlay(u, c)
@@ -410,7 +409,7 @@
 		reposition.AnimateHandCardPlay(ch, c, u)
 		return ""
 	}
-	return "Invalid play: No card has been played"
+	return "No card has been played"
 }
 
 func pressButton(b *staticimg.StaticImg, u *uistate.UIState) {