added Android examples
git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@13536 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
parent
2121df331c
commit
d6e1be5796
|
@ -916,7 +916,6 @@ ANDROID
|
|||
basedir="${android.dir}/lib/library"
|
||||
includes="scala/**/*.class"
|
||||
/>
|
||||
<!-- examples ? -->
|
||||
</target>
|
||||
|
||||
<target name="android" depends="init">
|
||||
|
@ -1827,6 +1826,11 @@ GENERATES A DISTRIBUTION
|
|||
</quicksbaz>
|
||||
<!-- Creates the Android package -->
|
||||
<if><isset property="android.supported"/><then>
|
||||
<copy todir="${dist.current.dir}/doc/scala-android/examples">
|
||||
<fileset dir="${docs.dir}/android-examples">
|
||||
<exclude name="**/R.java"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
<quicksbaz
|
||||
file="${dist.dir}/scala-android-${version.number}.sbp"
|
||||
adfile="${dist.dir}/scala-android-${version.number}.advert"
|
||||
|
@ -1835,6 +1839,7 @@ GENERATES A DISTRIBUTION
|
|||
desc="The Scala Android package contains everything needed to use Scala on Android."
|
||||
link="${sbaz.universe}/scala-android-${version.number}.sbp">
|
||||
<libset dir="${android.dir}/lib" includes="*.jar"/>
|
||||
<docset dir="${dist.current.dir}/doc/scala-android" includes="**"/>
|
||||
</quicksbaz>
|
||||
</then></if>
|
||||
</target>
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
* Copyright (C) 2007 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.google.android.notepad">
|
||||
<application android:icon="@drawable/app_notes"
|
||||
android:label="@string/app_name">
|
||||
<provider class="NotePadProvider"
|
||||
android:authorities="com.google.provider.NotePad" />
|
||||
|
||||
<activity class="NotesList" android:label="@string/title_notes_list">
|
||||
<intent-filter>
|
||||
<action android:value="android.intent.action.MAIN" />
|
||||
<category android:value="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:value="android.intent.action.VIEW" />
|
||||
<action android:value="android.intent.action.EDIT" />
|
||||
<action android:value="android.intent.action.PICK" />
|
||||
<category android:value="android.intent.category.DEFAULT" />
|
||||
<type android:value="vnd.android.cursor.dir/vnd.google.note" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:value="android.intent.action.GET_CONTENT" />
|
||||
<category android:value="android.intent.category.DEFAULT" />
|
||||
<type android:value="vnd.android.cursor.item/vnd.google.note" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity class="NoteEditor" android:label="@string/title_note">
|
||||
<!-- This filter says that we can view or edit the data of
|
||||
a single note -->
|
||||
<intent-filter android:label="@string/resolve_edit">
|
||||
<action android:value="android.intent.action.VIEW" />
|
||||
<action android:value="android.intent.action.EDIT" />
|
||||
<action android:value="com.google.android.notepad.action.EDIT_NOTE" />
|
||||
<category android:value="android.intent.category.DEFAULT" />
|
||||
<type android:value="vnd.android.cursor.item/vnd.google.note" />
|
||||
</intent-filter>
|
||||
|
||||
<!-- This filter says that we can create a new note inside
|
||||
of a directory of notes. -->
|
||||
<intent-filter>
|
||||
<action android:value="android.intent.action.INSERT" />
|
||||
<category android:value="android.intent.category.DEFAULT" />
|
||||
<type android:value="vnd.android.cursor.dir/vnd.google.note" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity class="TitleEditor" android:label="@string/title_edit_title"
|
||||
android:theme="@android:style/Theme.Dialog">
|
||||
<!-- This activity implements an alternative action that can be
|
||||
performed on notes: editing their title. It can be used as
|
||||
a default operation if the user invokes this action, and is
|
||||
available as an alternative action for any note data. -->
|
||||
<intent-filter android:label="@string/resolve_title">
|
||||
<!-- This is the action we perform. It is a custom action we
|
||||
define for our application, not a generic VIEW or EDIT
|
||||
action since we are not a general note viewer/editor. -->
|
||||
<action android:value="com.google.android.notepad.action.EDIT_TITLE" />
|
||||
<!-- DEFAULT: execute if being directly invoked. -->
|
||||
<category android:value="android.intent.category.DEFAULT" />
|
||||
<!-- ALTERNATIVE: show as an alternative action when the user is
|
||||
working with this type of data. -->
|
||||
<category android:value="android.intent.category.ALTERNATIVE" />
|
||||
<!-- SELECTED_ALTERNATIVE: show as an alternative action the user
|
||||
can perform when selecting this type of data. -->
|
||||
<category android:value="android.intent.category.SELECTED_ALTERNATIVE" />
|
||||
<!-- This is the data type we operate on. -->
|
||||
<type android:value="vnd.android.cursor.item/vnd.google.note" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
<?xml version="1.0" ?>
|
||||
<project name="NotePad" default="package">
|
||||
<property name="sdk-folder" value="/home/linuxsoft/apps/android-m3-rc22a" />
|
||||
<property name="android-tools" value="/home/linuxsoft/apps/android-m3-rc22a/tools" />
|
||||
|
||||
<!-- The intermediates directory -->
|
||||
<!-- Eclipse uses "bin" for its own output, so we do the same. -->
|
||||
<property name="outdir" value="bin" />
|
||||
|
||||
<!-- No user servicable parts below. -->
|
||||
|
||||
<!-- Input directories -->
|
||||
<property name="resource-dir" value="res" />
|
||||
<property name="asset-dir" value="assets" />
|
||||
<property name="srcdir" value="src" />
|
||||
|
||||
<!-- Output directories -->
|
||||
<property name="outdir-classes" value="${outdir}/classes" />
|
||||
|
||||
<!-- Create R.java in the source directory -->
|
||||
<property name="outdir-r" value="src" />
|
||||
|
||||
<!-- Intermediate files -->
|
||||
<property name="dex-file" value="classes.dex" />
|
||||
<property name="intermediate-dex" value="${outdir}/${dex-file}" />
|
||||
|
||||
<!-- The final package file to generate -->
|
||||
<property name="out-package" value="${outdir}/${ant.project.name}.apk" />
|
||||
|
||||
<!-- Tools -->
|
||||
<property name="aapt" value="${android-tools}/aapt" />
|
||||
<property name="aidl" value="${android-tools}/aidl" />
|
||||
<property name="dx" value="${android-tools}/dx" />
|
||||
<property name="zip" value="zip" />
|
||||
<property name="android-jar" value="${sdk-folder}/android.jar" />
|
||||
|
||||
<!-- Scala -->
|
||||
<property environment="env"/>
|
||||
<property name="scala.dir" value="${env.SCALA_HOME}"/>
|
||||
<property name="scala-compiler.jar" value="${scala.dir}/lib/scala-compiler.jar"/>
|
||||
<property name="scala-library.jar" value="${scala.dir}/lib/scala-library.jar"/>
|
||||
<property name="scala-android.jar" value="${scala.dir}/lib/scala-android.jar"/>
|
||||
<fail message="Missing library scala-android.jar (use sbaz to install it)">
|
||||
<condition><not><available file="${scala-android.jar}"/></not></condition>
|
||||
</fail>
|
||||
<property name="scala-depend.jar" value="${android-tools}/lib/scala-depend.jar"/>
|
||||
<path id="scala.path">
|
||||
<pathelement path="${scala-library.jar}"/>
|
||||
<pathelement path="${scala-compiler.jar}"/>
|
||||
</path>
|
||||
<path id="scalac.path">
|
||||
<pathelement path="${android-jar}"/>
|
||||
<pathelement path="${scala-library.jar}"/>
|
||||
</path>
|
||||
<taskdef
|
||||
resource="scala/tools/ant/antlib.xml"
|
||||
classpathref="scala.path"
|
||||
/>
|
||||
<macrodef name="smartjar">
|
||||
<attribute name="srcdir"/>
|
||||
<attribute name="basedir"/>
|
||||
<attribute name="classname"/>
|
||||
<attribute name="destfile"/>
|
||||
<sequential>
|
||||
<depend
|
||||
srcdir="@{srcdir}"
|
||||
destdir="@{basedir}" closure="true"
|
||||
cache="@{basedir}"
|
||||
classpath="${android-jar}"
|
||||
/>
|
||||
<java
|
||||
classname="ch.epfl.lamp.util.depend" output="@{basedir}/classes.dep"
|
||||
classpath="${scala-library.jar}${path.separator}${scala-depend.jar}">
|
||||
<arg line="@{basedir}${file.separator}dependencies.txt"/>
|
||||
<arg line="@{classname}"/>
|
||||
</java>
|
||||
<jar
|
||||
destfile="@{destfile}"
|
||||
basedir="@{basedir}"
|
||||
includesfile="@{basedir}/classes.dep"
|
||||
/>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
|
||||
<!-- Rules -->
|
||||
|
||||
<!-- Create the output directories if they don't exist yet. -->
|
||||
<target name="dirs">
|
||||
<mkdir dir="${outdir}" />
|
||||
<mkdir dir="${outdir-classes}" />
|
||||
</target>
|
||||
|
||||
<!-- Generate the R.java file for this project's resources. -->
|
||||
<target name="resource-src" depends="dirs">
|
||||
<echo>Generating R.java...</echo>
|
||||
<exec executable="${aapt}" failonerror="true">
|
||||
<arg value="compile" />
|
||||
<arg value="-m" />
|
||||
<arg value="-J" />
|
||||
<arg value="${outdir-r}" />
|
||||
<arg value="-M" />
|
||||
<arg value="AndroidManifest.xml" />
|
||||
<arg value="-S" />
|
||||
<arg value="${resource-dir}" />
|
||||
<arg value="-I" />
|
||||
<arg value="${android-jar}" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- Generate java classes from .aidl files. -->
|
||||
<target name="aidl" depends="dirs">
|
||||
<apply executable="${aidl}" failonerror="true">
|
||||
<fileset dir="${srcdir}">
|
||||
<include name="**/*.aidl"/>
|
||||
</fileset>
|
||||
</apply>
|
||||
</target>
|
||||
|
||||
<!-- Compile this project's .java files into .class files. -->
|
||||
<target name="compile" depends="dirs, resource-src, aidl">
|
||||
<javac encoding="ascii" target="1.5" debug="true" extdirs=""
|
||||
srcdir="."
|
||||
destdir="${outdir-classes}"
|
||||
bootclasspath="${android-jar}" />
|
||||
<scalac encoding="ascii" target="jvm-1.5"
|
||||
srcdir="${srcdir}"
|
||||
destdir="${outdir-classes}"
|
||||
bootclasspathref="scalac.path" />
|
||||
<unjar src="${scala-android.jar}" dest="${outdir-classes}"/>
|
||||
<smartjar
|
||||
srcdir="${srcdir}"
|
||||
basedir="${outdir-classes}"
|
||||
classname="com.google.android.notepad.NotePad"
|
||||
destfile="${outdir}/${ant.project.name}.jar"
|
||||
/>
|
||||
<delete includeemptydirs="true">
|
||||
<fileset dir="${outdir-classes}" includes="**/*"/>
|
||||
</delete>
|
||||
<unjar src="${outdir}/${ant.project.name}.jar" dest="${outdir-classes}"/>
|
||||
</target>
|
||||
|
||||
<!-- Convert this project's .class files into .dex files. -->
|
||||
<target name="dex" depends="compile">
|
||||
<exec executable="${dx}" failonerror="true">
|
||||
<arg value="-JXmx384M" />
|
||||
<arg value="--dex" />
|
||||
<arg value="--output=${intermediate-dex}" />
|
||||
<arg value="--locals=full" />
|
||||
<arg value="--positions=lines" />
|
||||
<arg path="${outdir-classes}" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- Put the project's resources into the output package file. -->
|
||||
<target name="package-res-and-assets">
|
||||
<echo>Packaging resources and assets...</echo>
|
||||
<exec executable="${aapt}" failonerror="true">
|
||||
<arg value="package" />
|
||||
<arg value="-f" />
|
||||
<arg value="-c" />
|
||||
<arg value="-M" />
|
||||
<arg value="AndroidManifest.xml" />
|
||||
<arg value="-S" />
|
||||
<arg value="${resource-dir}" />
|
||||
<arg value="-A" />
|
||||
<arg value="${asset-dir}" />
|
||||
<arg value="-I" />
|
||||
<arg value="${android-jar}" />
|
||||
<arg value="${out-package}" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- Same as package-res-and-assets, but without "-A ${asset-dir}" -->
|
||||
<target name="package-res-no-assets">
|
||||
<echo>Packaging resources...</echo>
|
||||
<exec executable="${aapt}" failonerror="true">
|
||||
<arg value="package" />
|
||||
<arg value="-f" />
|
||||
<arg value="-c" />
|
||||
<arg value="-M" />
|
||||
<arg value="AndroidManifest.xml" />
|
||||
<arg value="-S" />
|
||||
<arg value="${resource-dir}" />
|
||||
<!-- No assets directory -->
|
||||
<arg value="-I" />
|
||||
<arg value="${android-jar}" />
|
||||
<arg value="${out-package}" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- Invoke the proper target depending on whether or not
|
||||
an assets directory is present. -->
|
||||
<!-- TODO: find a nicer way to include the "-A ${asset-dir}" argument
|
||||
only when the assets dir exists. -->
|
||||
<target name="package-res">
|
||||
<available file="${asset-dir}" type="dir"
|
||||
property="res-target" value="and-assets" />
|
||||
<property name="res-target" value="no-assets" />
|
||||
<antcall target="package-res-${res-target}" />
|
||||
</target>
|
||||
|
||||
<!-- Put the project's .class files into the output package file. -->
|
||||
<target name="package-java" depends="compile, package-res">
|
||||
<echo>Packaging java...</echo>
|
||||
<jar destfile="${out-package}"
|
||||
basedir="${outdir-classes}"
|
||||
update="true" />
|
||||
</target>
|
||||
|
||||
<!-- Put the project's .dex files into the output package file. -->
|
||||
<target name="package-dex" depends="dex, package-res">
|
||||
<echo>Packaging dex...</echo>
|
||||
<exec executable="${zip}" failonerror="true">
|
||||
<arg value="-qj" />
|
||||
<arg value="${out-package}" />
|
||||
<arg value="${intermediate-dex}" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- Create the package file for this project from the sources. -->
|
||||
<target name="package" depends="package-dex" />
|
||||
</project>
|
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
* Copyright (C) 2007 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
-->
|
||||
|
||||
<view xmlns:android="http://schemas.android.com/apk/res/android" class="com.google.android.notepad.NoteEditor$MyEditText" id="@+id/note"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="#ffffff"
|
||||
android:padding="10dip"
|
||||
android:scrollbars="vertical"
|
||||
android:fadingEdge="vertical" />
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
* Copyright (C) 2007 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
-->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="6dip"
|
||||
android:paddingRight="6dip"
|
||||
android:paddingBottom="3dip">
|
||||
|
||||
<EditText id="@+id/title"
|
||||
android:maxLines="1"
|
||||
android:layout_marginTop="2dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:ems="25"
|
||||
android:layout_height="wrap_content"
|
||||
android:autoText="true"
|
||||
android:capitalize="sentences"
|
||||
android:scrollHorizontally="true" />
|
||||
|
||||
<Button id="@+id/ok"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="right"
|
||||
android:text="@string/button_ok" />
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
* Copyright (C) 2007 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="menu_delete">Ðéļéţé</string>
|
||||
<string name="menu_insert">Ådd ñöţé</string>
|
||||
<string name="menu_revert">®évérţ</string>
|
||||
<string name="menu_discard">Ðîšçård</string>
|
||||
|
||||
<string name="resolve_edit">Édîţ ñöţé</string>
|
||||
<string name="resolve_title">Édîţ ţîţļé</string>
|
||||
|
||||
<string name="title_create">Çréåţé ñöţé</string>
|
||||
<string name="title_edit">Édîţ ñöţé</string>
|
||||
<string name="title_notes_list">Ñöţé þåd</string>
|
||||
<string name="title_note">Ñöţé</string>
|
||||
<string name="title_edit_title">Ñöţé ţîţļé:</string>
|
||||
|
||||
<string name="app_name">Ñöţé Þåd</string>
|
||||
|
||||
<string name="button_ok">ÖĶ</string>
|
||||
|
||||
<string name="error_title">Érrör</string>
|
||||
<string name="error_message">Érrör löading nöté</string>
|
||||
</resources>
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
* Copyright (C) 2007 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<drawable name="even_stripe">#e5edfa</drawable>
|
||||
<drawable name="odd_stripe">#ffffffff</drawable>
|
||||
</resources>
|
|
@ -0,0 +1,39 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
* Copyright (C) 2007 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="menu_delete">Delete</string>
|
||||
<string name="menu_insert">Add note</string>
|
||||
<string name="menu_revert">Revert</string>
|
||||
<string name="menu_discard">Discard</string>
|
||||
|
||||
<string name="resolve_edit">Edit note</string>
|
||||
<string name="resolve_title">Edit title</string>
|
||||
|
||||
<string name="title_create">Create note</string>
|
||||
<string name="title_edit">Edit note</string>
|
||||
<string name="title_notes_list">Note pad</string>
|
||||
<string name="title_note">Note</string>
|
||||
<string name="title_edit_title">Note title:</string>
|
||||
|
||||
<string name="app_name">Note Pad</string>
|
||||
|
||||
<string name="button_ok">OK</string>
|
||||
|
||||
<string name="error_title">Error</string>
|
||||
<string name="error_message">Error loading note</string>
|
||||
</resources>
|
Binary file not shown.
After Width: | Height: | Size: 3.9 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
|
@ -0,0 +1,328 @@
|
|||
/*
|
||||
* Copyright (C) 2007 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.notepad
|
||||
|
||||
import com.google.provider.NotePad
|
||||
|
||||
import _root_.android.app.Activity
|
||||
import _root_.android.app.Activity._
|
||||
import _root_.android.content.{ComponentName, Context, Intent}
|
||||
import _root_.android.database.Cursor
|
||||
import _root_.android.graphics.{Canvas, Paint, Rect}
|
||||
import _root_.android.net.ContentURI
|
||||
import _root_.android.os.Bundle
|
||||
import _root_.android.text.TextUtils
|
||||
import _root_.android.util.{AttributeSet, Log, Config}
|
||||
import _root_.android.view.{KeyEvent, Menu}
|
||||
import _root_.android.widget.EditText
|
||||
|
||||
import java.util.Map
|
||||
|
||||
/**
|
||||
* A generic activity for editing a note in a database. This can be used
|
||||
* either to simply view a note (Intent.VIEW_ACTION), view and edit a note
|
||||
* (Intent.EDIT_ACTION), or create a new note (Intent.INSERT_ACTION).
|
||||
*/
|
||||
object NoteEditor {
|
||||
private val TAG = "Notes"
|
||||
|
||||
private val NOTE_INDEX = 1
|
||||
private val TITLE_INDEX = 2
|
||||
private val MODIFIED_INDEX = 3
|
||||
|
||||
/**
|
||||
* Standard projection for the interesting columns of a normal note.
|
||||
*/
|
||||
private val PROJECTION = Array(
|
||||
NotePad.Notes._ID, // 0
|
||||
NotePad.Notes.NOTE, // 1
|
||||
NotePad.Notes.TITLE, // 2
|
||||
NotePad.Notes.MODIFIED_DATE // 3
|
||||
)
|
||||
|
||||
// This is our state data that is stored when freezing.
|
||||
private val ORIGINAL_CONTENT = "origContent"
|
||||
|
||||
// Identifiers for our menu items.
|
||||
private val REVERT_ID = Menu.FIRST
|
||||
private val DISCARD_ID = Menu.FIRST + 1
|
||||
private val DELETE_ID = Menu.FIRST + 2
|
||||
|
||||
// The different distinct states the activity can be run in.
|
||||
private val STATE_UNDEF = -1
|
||||
private val STATE_EDIT = 0
|
||||
private val STATE_INSERT = 1
|
||||
|
||||
// we need this constructor for ViewInflate
|
||||
class MyEditText(context: Context, attrs: AttributeSet, params: Map)
|
||||
extends EditText(context, attrs, params) {
|
||||
private val mRect = new Rect()
|
||||
private val mPaint = new Paint()
|
||||
mPaint setStyle Paint.Style.STROKE
|
||||
mPaint setColor 0xFF0000FF
|
||||
|
||||
override protected def onDraw(canvas: Canvas) {
|
||||
val count = getLineCount()
|
||||
val r = mRect
|
||||
val paint = mPaint
|
||||
|
||||
for (i <- 0 until count) {
|
||||
val baseline = getLineBounds(i, r)
|
||||
canvas.drawLine(r.left, baseline + 1, r.right, baseline + 1, paint)
|
||||
}
|
||||
super.onDraw(canvas)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NoteEditor extends Activity {
|
||||
import NoteEditor._ // companion object
|
||||
|
||||
private var mState = STATE_UNDEF
|
||||
private var mNoteOnly = false
|
||||
private var mURI: ContentURI = _
|
||||
private var mCursor: Cursor = null
|
||||
private var mText: EditText = null
|
||||
private var mOriginalContent: String = ""
|
||||
|
||||
override protected def onCreate(icicle: Bundle) {
|
||||
super.onCreate(icicle)
|
||||
|
||||
val intent = getIntent()
|
||||
//val type = intent.resolveType(this)
|
||||
|
||||
// Do some setup based on the action being performed.
|
||||
|
||||
val action = intent.getAction()
|
||||
if (action equals Intent.EDIT_ACTION) {
|
||||
// Requested to edit: set that state, and the data being edited.
|
||||
mState = STATE_EDIT
|
||||
mURI = intent.getData()
|
||||
|
||||
} else if (action equals Intent.INSERT_ACTION) {
|
||||
// Requested to insert: set that state, and create a new entry
|
||||
// in the container.
|
||||
mState = STATE_INSERT
|
||||
mURI = getContentResolver().insert(intent.getData(), null)
|
||||
|
||||
// If we were unable to create a new note, then just finish
|
||||
// this activity. A RESULT_CANCELED will be sent back to the
|
||||
// original activity if they requested a result.
|
||||
if (mURI == null) {
|
||||
Log.e("Notes", "Failed to insert new note into " +
|
||||
getIntent().getData())
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
// The new entry was created, so assume all will end well and
|
||||
// set the result to be returned.
|
||||
setResult(RESULT_OK, mURI.toString())
|
||||
|
||||
} else {
|
||||
// Whoops, unknown action! Bail.
|
||||
Log.e(TAG, "Unknown action, exiting")
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
// Set the layout for this activity. You can find it
|
||||
// in res/layout/hello_activity.xml
|
||||
setContentView(R.layout.note_editor)
|
||||
|
||||
// The text view for our note, identified by its ID in the XML file.
|
||||
mText = findViewById(R.id.note).asInstanceOf[EditText]
|
||||
|
||||
// Get the note!
|
||||
mCursor = managedQuery(mURI, PROJECTION, null, null)
|
||||
|
||||
// If an instance of this activity had previously stopped, we can
|
||||
// get the original text it started with.
|
||||
if (icicle != null)
|
||||
mOriginalContent = icicle getString ORIGINAL_CONTENT
|
||||
}
|
||||
|
||||
override protected def onResume() {
|
||||
super.onResume()
|
||||
|
||||
// If we didn't have any trouble retrieving the data, it is now
|
||||
// time to get at the stuff.
|
||||
if (mCursor != null) {
|
||||
// Make sure we are at the one and only row in the cursor.
|
||||
mCursor.first()
|
||||
|
||||
// Modify our overall title depending on the mode we are running in.
|
||||
if (mState == STATE_EDIT)
|
||||
setTitle(getText(R.string.title_edit))
|
||||
else if (mState == STATE_INSERT)
|
||||
setTitle(getText(R.string.title_create))
|
||||
|
||||
// This is a little nasty: we be resumed after previously being
|
||||
// paused/stopped. We want to re-retrieve the data to make sure
|
||||
// we are still accurately showing what is in the cursor... but
|
||||
// we don't want to lose any UI state like the current cursor
|
||||
// position. This trick accomplishes that. In the future we
|
||||
// should have a better API for doing this...
|
||||
val curState = mText.saveState()
|
||||
val note = mCursor getString NOTE_INDEX
|
||||
mText setText note
|
||||
mText restoreState curState
|
||||
|
||||
// If we hadn't previously retrieved the original text, do so
|
||||
// now. This allows the user to revert their changes.
|
||||
if (mOriginalContent == null)
|
||||
mOriginalContent = note
|
||||
} else {
|
||||
setTitle(getText(R.string.error_title))
|
||||
mText setText getText(R.string.error_message)
|
||||
}
|
||||
}
|
||||
|
||||
override protected def onFreeze(outState: Bundle) {
|
||||
// Save away the original text, so we still have it if the activity
|
||||
// needs to be killed while paused.
|
||||
outState.putString(ORIGINAL_CONTENT, mOriginalContent)
|
||||
}
|
||||
|
||||
override protected def onPause() {
|
||||
super.onPause()
|
||||
|
||||
// The user is going somewhere else, so make sure their current
|
||||
// changes are safely saved away in the provider. We don't need
|
||||
// to do this if only editing.
|
||||
if (mCursor != null) {
|
||||
val text = mText.getText().toString()
|
||||
val length = text.length()
|
||||
|
||||
// If this activity is finished, and there is no text, then we
|
||||
// do something a little special: simply delete the note entry.
|
||||
// Note that we do this both for editing and inserting... it
|
||||
// would be reasonable to only do it when inserting.
|
||||
if (isFinishing() && (length == 0) && !mNoteOnly) {
|
||||
setResult(RESULT_CANCELED)
|
||||
deleteNote()
|
||||
|
||||
// Get out updates into the provider.
|
||||
} else {
|
||||
// This stuff is only done when working with a full-fledged note.
|
||||
if (!mNoteOnly) {
|
||||
// Bump the modification time to now.
|
||||
mCursor.updateLong(MODIFIED_INDEX, System.currentTimeMillis())
|
||||
|
||||
// If we are creating a new note, then we want to also create
|
||||
// an initial title for it.
|
||||
if (mState == STATE_INSERT) {
|
||||
var title = text.substring(0, Math.min(30, length))
|
||||
if (length > 30) {
|
||||
val lastSpace = title lastIndexOf ' '
|
||||
if (lastSpace > 0)
|
||||
title = title.substring(0, lastSpace)
|
||||
}
|
||||
mCursor.updateString(TITLE_INDEX, title)
|
||||
}
|
||||
}
|
||||
|
||||
// Write our text back into the provider.
|
||||
mCursor.updateString(NOTE_INDEX, text)
|
||||
|
||||
// Commit all of our changes to persistent storage. Note the
|
||||
// use of managedCommitUpdates() instead of
|
||||
// mCursor.commitUpdates() -- this lets Activity take care of
|
||||
// requerying the new data if needed.
|
||||
managedCommitUpdates(mCursor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override def onCreateOptionsMenu(menu: Menu): Boolean = {
|
||||
super.onCreateOptionsMenu(menu)
|
||||
|
||||
// Build the menus that are shown when editing.
|
||||
if (mState == STATE_EDIT) {
|
||||
menu.add(0, REVERT_ID, R.string.menu_revert).setShortcut(
|
||||
KeyEvent.KEYCODE_0, 0, KeyEvent.KEYCODE_R)
|
||||
if (!mNoteOnly)
|
||||
menu.add(0, DELETE_ID, R.string.menu_delete).setShortcut(
|
||||
KeyEvent.KEYCODE_1, 0, KeyEvent.KEYCODE_D)
|
||||
|
||||
// Build the menus that are shown when inserting.
|
||||
} else
|
||||
menu.add(0, DISCARD_ID, R.string.menu_discard).setShortcut(
|
||||
KeyEvent.KEYCODE_0, 0, KeyEvent.KEYCODE_D)
|
||||
|
||||
// If we are working on a real honest-to-ghod note, then append to the
|
||||
// menu items for any other activities that can do stuff with it
|
||||
// as well. This does a query on the system for any activities that
|
||||
// implement the ALTERNATIVE_ACTION for our data, adding a menu item
|
||||
// for each one that is found.
|
||||
if (!mNoteOnly) {
|
||||
val intent = new Intent(null, getIntent().getData())
|
||||
intent addCategory Intent.ALTERNATIVE_CATEGORY
|
||||
menu.addIntentOptions(
|
||||
Menu.ALTERNATIVE, 0,
|
||||
new ComponentName(this, classOf[NoteEditor]), null,
|
||||
intent, 0, null)
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
override def onOptionsItemSelected(item: Menu.Item): Boolean = {
|
||||
// Handle all of the possible menu actions.
|
||||
item.getId() match {
|
||||
case DELETE_ID =>
|
||||
deleteNote()
|
||||
finish()
|
||||
case DISCARD_ID =>
|
||||
cancelNote()
|
||||
case REVERT_ID =>
|
||||
cancelNote()
|
||||
case _ =>
|
||||
}
|
||||
super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
/**
|
||||
* Take care of cancelling work on a note. Deletes the note if we
|
||||
* had created it, otherwise reverts to the original text.
|
||||
*/
|
||||
private final def cancelNote() {
|
||||
if (mCursor != null) {
|
||||
if (mState == STATE_EDIT) {
|
||||
mCursor.updateString(NOTE_INDEX, mOriginalContent)
|
||||
mCursor.commitUpdates()
|
||||
mCursor.deactivate()
|
||||
mCursor = null
|
||||
} else if (mState == STATE_INSERT)
|
||||
deleteNote()
|
||||
}
|
||||
setResult(RESULT_CANCELED)
|
||||
finish()
|
||||
}
|
||||
|
||||
/**
|
||||
* Take care of deleting a note. Simply deletes the entry.
|
||||
*/
|
||||
private final def deleteNote() {
|
||||
if (mCursor != null) {
|
||||
mText setText ""
|
||||
mCursor.deleteRow()
|
||||
mCursor.deactivate()
|
||||
mCursor = null
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Copyright (C) 2007 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.notepad
|
||||
|
||||
import com.google.provider.NotePad
|
||||
|
||||
import _root_.android.content.{ContentProvider, ContentProviderDatabaseHelper,
|
||||
ContentURIParser, ContentValues, QueryBuilder,
|
||||
Resources}
|
||||
import _root_.android.database.{Cursor, SQLException}
|
||||
import _root_.android.database.sqlite.SQLiteDatabase
|
||||
import _root_.android.net.ContentURI
|
||||
import _root_.android.text.TextUtils
|
||||
import _root_.android.util.Log
|
||||
|
||||
import java.util.HashMap // note: setProjectionMap expects a Java map
|
||||
|
||||
/**
|
||||
* Provides access to a database of notes. Each note has a title, the note
|
||||
* itself, a creation date and a modified data.
|
||||
*
|
||||
*/
|
||||
object NotePadProvider {
|
||||
private val TAG = "NotePadProvider"
|
||||
private val DATABASE_NAME = "note_pad.db"
|
||||
private val DATABASE_VERSION = 2
|
||||
|
||||
private val NOTES_LIST_PROJECTION_MAP = new HashMap/*[String, String]*/()
|
||||
NOTES_LIST_PROJECTION_MAP.put(NotePad.Notes._ID, "_id")
|
||||
NOTES_LIST_PROJECTION_MAP.put(NotePad.Notes.TITLE, "title")
|
||||
NOTES_LIST_PROJECTION_MAP.put(NotePad.Notes.NOTE, "note")
|
||||
NOTES_LIST_PROJECTION_MAP.put(NotePad.Notes.CREATED_DATE, "created")
|
||||
NOTES_LIST_PROJECTION_MAP.put(NotePad.Notes.MODIFIED_DATE, "modified")
|
||||
|
||||
private val NOTES = 1
|
||||
private val NOTE_ID = 2
|
||||
|
||||
private val URL_MATCHER = new ContentURIParser(ContentURIParser.NO_MATCH)
|
||||
URL_MATCHER.addURI("com.google.provider.NotePad", "notes", NOTES)
|
||||
URL_MATCHER.addURI("com.google.provider.NotePad", "notes/#", NOTE_ID)
|
||||
|
||||
private class DatabaseHelper extends ContentProviderDatabaseHelper {
|
||||
override def onCreate(db: SQLiteDatabase) {
|
||||
db execSQL "CREATE TABLE notes (_id INTEGER PRIMARY KEY," +
|
||||
"title TEXT," + "note TEXT," + "created INTEGER," +
|
||||
"modified INTEGER" + ");"
|
||||
}
|
||||
|
||||
override def onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||
Log.w(TAG, "Upgrading database from version " + oldVersion + " to " +
|
||||
newVersion + ", which will destroy all old data")
|
||||
db execSQL "DROP TABLE IF EXISTS notes"
|
||||
onCreate(db)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NotePadProvider extends ContentProvider {
|
||||
import NotePadProvider._
|
||||
|
||||
private var mDB: SQLiteDatabase = _
|
||||
|
||||
override def onCreate(): Boolean = {
|
||||
val dbHelper = new DatabaseHelper()
|
||||
mDB = dbHelper.openDatabase(getContext(), DATABASE_NAME, null, DATABASE_VERSION)
|
||||
mDB != null
|
||||
}
|
||||
|
||||
override def query(url: ContentURI, projection: Array[String],
|
||||
selection: String, selectionArgs: Array[String],
|
||||
groupBy: String, having: String, sort: String): Cursor = {
|
||||
val qb = new QueryBuilder()
|
||||
|
||||
(URL_MATCHER `match` url) match {
|
||||
case NOTES =>
|
||||
qb setTables "notes"
|
||||
qb setProjectionMap NOTES_LIST_PROJECTION_MAP
|
||||
|
||||
case NOTE_ID =>
|
||||
qb setTables "notes"
|
||||
qb appendWhere ("_id=" + url.getPathSegment(1))
|
||||
|
||||
case _ =>
|
||||
throw new IllegalArgumentException("Unknown URL " + url)
|
||||
}
|
||||
|
||||
// If no sort order is specified use the default
|
||||
val orderBy =
|
||||
if (TextUtils isEmpty sort)
|
||||
NotePad.Notes.DEFAULT_SORT_ORDER
|
||||
else
|
||||
sort
|
||||
|
||||
val c = qb.query(mDB, projection, selection, selectionArgs, groupBy,
|
||||
having, orderBy)
|
||||
c.setNotificationUri(getContext().getContentResolver(), url);
|
||||
c
|
||||
}
|
||||
|
||||
override def getType(url: ContentURI): String = (URL_MATCHER `match` url) match {
|
||||
case NOTES =>
|
||||
"vnd.android.cursor.dir/vnd.google.note"
|
||||
case NOTE_ID =>
|
||||
"vnd.android.cursor.item/vnd.google.note"
|
||||
case _ =>
|
||||
throw new IllegalArgumentException("Unknown URL " + url)
|
||||
}
|
||||
|
||||
override def insert(url: ContentURI, initialValues: ContentValues): ContentURI = {
|
||||
val values =
|
||||
if (initialValues != null)
|
||||
new ContentValues(initialValues)
|
||||
else
|
||||
new ContentValues()
|
||||
|
||||
if ((URL_MATCHER `match` url) != NOTES)
|
||||
throw new IllegalArgumentException("Unknown URL " + url)
|
||||
|
||||
val now = System.currentTimeMillis()
|
||||
val r = Resources.getSystem()
|
||||
|
||||
// Make sure that the fields are all set
|
||||
if (! values.containsKey(NotePad.Notes.CREATED_DATE))
|
||||
values.put(NotePad.Notes.CREATED_DATE, now)
|
||||
|
||||
if (! values.containsKey(NotePad.Notes.MODIFIED_DATE))
|
||||
values.put(NotePad.Notes.MODIFIED_DATE, now)
|
||||
|
||||
if (! values.containsKey(NotePad.Notes.TITLE))
|
||||
values.put(NotePad.Notes.TITLE, r.getString(_root_.android.R.string.untitled))
|
||||
|
||||
if (! values.containsKey(NotePad.Notes.NOTE))
|
||||
values.put(NotePad.Notes.NOTE, "")
|
||||
|
||||
val rowID = mDB.insert("notes", "note", values)
|
||||
if (rowID > 0) {
|
||||
val uri = NotePad.Notes.CONTENT_URI addId rowID
|
||||
getContext().getContentResolver().notifyChange(uri, null)
|
||||
uri
|
||||
} else
|
||||
throw new SQLException("Failed to insert row into " + url)
|
||||
}
|
||||
|
||||
override def delete(url: ContentURI, where: String, whereArgs: Array[String]): Int = {
|
||||
val count = (URL_MATCHER `match` url) match {
|
||||
case NOTES =>
|
||||
mDB.delete("note_pad", where, whereArgs)
|
||||
|
||||
case NOTE_ID =>
|
||||
val segment = url.getPathSegment(1)
|
||||
//rowId = Long.parseLong(segment);
|
||||
mDB.delete("notes", "_id=" +
|
||||
segment +
|
||||
(if (!TextUtils.isEmpty(where)) " AND (" + where + ')' else ""),
|
||||
whereArgs)
|
||||
|
||||
case _ =>
|
||||
throw new IllegalArgumentException("Unknown URL " + url)
|
||||
}
|
||||
|
||||
getContext().getContentResolver().notifyChange(url, null)
|
||||
count
|
||||
}
|
||||
|
||||
override def update(url: ContentURI, values: ContentValues,
|
||||
where: String, whereArgs: Array[String]): Int = {
|
||||
val count = (URL_MATCHER `match` url) match {
|
||||
case NOTES =>
|
||||
mDB.update("notes", values, where, whereArgs)
|
||||
|
||||
case NOTE_ID =>
|
||||
val segment = url getPathSegment 1
|
||||
mDB.update("notes", values, "_id=" +
|
||||
segment +
|
||||
(if (!TextUtils.isEmpty(where)) " AND (" + where + ')'
|
||||
else ""),
|
||||
whereArgs)
|
||||
|
||||
case _ =>
|
||||
throw new IllegalArgumentException("Unknown URL " + url)
|
||||
}
|
||||
|
||||
getContext().getContentResolver().notifyChange(url, null)
|
||||
count
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Copyright (C) 2007 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.notepad
|
||||
|
||||
import com.google.provider.NotePad
|
||||
|
||||
import _root_.android.app.Activity._
|
||||
import _root_.android.app.ListActivity
|
||||
import _root_.android.content.{ComponentName, Intent}
|
||||
import _root_.android.database.Cursor
|
||||
import _root_.android.graphics.drawable.Drawable
|
||||
import _root_.android.net.ContentURI
|
||||
import _root_.android.os.Bundle
|
||||
import _root_.android.view.{KeyEvent, Menu, View}
|
||||
import _root_.android.view.View.MeasureSpec
|
||||
import _root_.android.widget.{ListAdapter, ListView, SimpleCursorAdapter, TextView}
|
||||
|
||||
|
||||
/**
|
||||
* Displays a list of notes. Will display notes from the ContentUri
|
||||
* provided int the intent if there is one, otherwise uses the default list
|
||||
* from the
|
||||
*
|
||||
*/
|
||||
object NotesList {
|
||||
// Menu item Ids
|
||||
val DELETE_ID = Menu.FIRST
|
||||
val INSERT_ID = Menu.FIRST + 1
|
||||
|
||||
/**
|
||||
* The columns we are interested in from the database
|
||||
*/
|
||||
private val PROJECTION = Array(
|
||||
NotePad.Notes._ID,
|
||||
NotePad.Notes.TITLE
|
||||
)
|
||||
}
|
||||
|
||||
class NotesList extends ListActivity {
|
||||
import NotesList._ // companion object
|
||||
|
||||
/**
|
||||
* Cursor which holds list of all notes
|
||||
*/
|
||||
private var mCursor: Cursor = _
|
||||
|
||||
override protected def onCreate(icicle: Bundle) {
|
||||
super.onCreate(icicle)
|
||||
|
||||
setDefaultKeyMode(SHORTCUT_DEFAULT_KEYS)
|
||||
|
||||
// If no data was given in the intent (because we were started
|
||||
// as a MAIN activity), then use our default content provider.
|
||||
val intent = getIntent()
|
||||
if (intent.getData() == null)
|
||||
intent setData NotePad.Notes.CONTENT_URI
|
||||
|
||||
setupListStripes()
|
||||
|
||||
mCursor = managedQuery(getIntent().getData(), PROJECTION, null, null)
|
||||
|
||||
// Used to map notes entries from the database to views
|
||||
val adapter = new SimpleCursorAdapter(this,
|
||||
_root_.android.R.layout.simple_list_item_1, mCursor,
|
||||
Array(NotePad.Notes.TITLE), Array(_root_.android.R.id.text1))
|
||||
setListAdapter(adapter)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add stripes to the list view.
|
||||
*/
|
||||
private def setupListStripes() {
|
||||
// Get Drawables for alternating stripes
|
||||
val lineBackgrounds = new Array[Drawable](2)
|
||||
|
||||
lineBackgrounds(0) = getResources().getDrawable(R.drawable.even_stripe)
|
||||
lineBackgrounds(1) = getResources().getDrawable(R.drawable.odd_stripe)
|
||||
|
||||
// Make and measure a sample TextView of the sort our adapter will
|
||||
// return
|
||||
val view = getViewInflate().
|
||||
inflate(_root_.android.R.layout.simple_list_item_1, null, null)
|
||||
|
||||
val v = view.findViewById(_root_.android.R.id.text1).asInstanceOf[TextView]
|
||||
v setText "X"
|
||||
// Make it 100 pixels wide, and let it choose its own height.
|
||||
v.measure(MeasureSpec.makeMeasureSpec(View.MeasureSpec.EXACTLY, 100),
|
||||
MeasureSpec.makeMeasureSpec(View.MeasureSpec.UNSPECIFIED, 0))
|
||||
val height = v.getMeasuredHeight()
|
||||
getListView().setStripes(lineBackgrounds, height)
|
||||
}
|
||||
|
||||
override def onCreateOptionsMenu(menu: Menu): Boolean = {
|
||||
super.onCreateOptionsMenu(menu)
|
||||
|
||||
// This is our one standard application action -- inserting a
|
||||
// new note into the list.
|
||||
menu.add(0, INSERT_ID, R.string.menu_insert).setShortcut(
|
||||
KeyEvent.KEYCODE_3, 0, KeyEvent.KEYCODE_A)
|
||||
|
||||
// Generate any additional actions that can be performed on the
|
||||
// overall list. In a normal install, there are no additional
|
||||
// actions found here, but this allows other applications to extend
|
||||
// our menu with their own actions.
|
||||
val intent = new Intent(null, getIntent().getData())
|
||||
intent addCategory Intent.ALTERNATIVE_CATEGORY
|
||||
menu.addIntentOptions(
|
||||
Menu.ALTERNATIVE, 0, new ComponentName(this, classOf[NotesList]),
|
||||
null, intent, 0, null)
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
override def onPrepareOptionsMenu(menu: Menu): Boolean = {
|
||||
super.onPrepareOptionsMenu(menu)
|
||||
val haveItems = mCursor.count() > 0
|
||||
|
||||
// If there are any notes in the list (which implies that one of
|
||||
// them is selected), then we need to generate the actions that
|
||||
// can be performed on the current selection. This will be a combination
|
||||
// of our own specific actions along with any extensions that can be
|
||||
// found.
|
||||
if (haveItems) {
|
||||
// This is the selected item.
|
||||
val uri = getIntent().getData() addId getSelectionRowID()
|
||||
|
||||
// Build menu... always starts with the EDIT action...
|
||||
val specifics = Array(new Intent(Intent.EDIT_ACTION, uri))
|
||||
val items = new Array[Menu.Item](1)
|
||||
|
||||
// ... is followed by whatever other actions are available...
|
||||
val intent = new Intent(null, uri)
|
||||
intent addCategory Intent.SELECTED_ALTERNATIVE_CATEGORY
|
||||
menu.addIntentOptions(Menu.SELECTED_ALTERNATIVE, 0, null, specifics,
|
||||
intent, Menu.NO_SEPARATOR_AFTER, items)
|
||||
|
||||
// ... and ends with the delete command.
|
||||
menu.add(Menu.SELECTED_ALTERNATIVE, DELETE_ID, R.string.menu_delete).
|
||||
setShortcut(KeyEvent.KEYCODE_2, 0, KeyEvent.KEYCODE_D)
|
||||
menu.addSeparator(Menu.SELECTED_ALTERNATIVE, 0)
|
||||
|
||||
// Give a shortcut to the edit action.
|
||||
if (items(0) != null)
|
||||
items(0).setShortcut(KeyEvent.KEYCODE_1, 0, KeyEvent.KEYCODE_E)
|
||||
}
|
||||
else
|
||||
menu removeGroup Menu.SELECTED_ALTERNATIVE
|
||||
|
||||
// Make sure the delete action is disabled if there are no items.
|
||||
menu.setItemShown(DELETE_ID, haveItems)
|
||||
true
|
||||
}
|
||||
|
||||
override def onOptionsItemSelected(item: Menu.Item): Boolean = item.getId() match {
|
||||
case DELETE_ID =>
|
||||
deleteItem()
|
||||
true
|
||||
case INSERT_ID =>
|
||||
insertItem()
|
||||
true
|
||||
case _ =>
|
||||
super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override protected def onListItemClick(l: ListView, v: View,
|
||||
position: Int, id: Long) {
|
||||
val url = getIntent().getData() addId getSelectionRowID()
|
||||
|
||||
val action = getIntent().getAction()
|
||||
if ((Intent.PICK_ACTION equals action) ||
|
||||
(Intent.GET_CONTENT_ACTION equals action))
|
||||
// The caller is waiting for us to return a note selected by
|
||||
// the user. The have clicked on one, so return it now.
|
||||
setResult(RESULT_OK, url.toString())
|
||||
else
|
||||
// Launch activity to view/edit the currently selected item
|
||||
startActivity(new Intent(Intent.EDIT_ACTION, url))
|
||||
}
|
||||
|
||||
private final def deleteItem() {
|
||||
mCursor moveTo getSelection()
|
||||
mCursor.deleteRow()
|
||||
}
|
||||
|
||||
private final def insertItem() {
|
||||
// Launch activity to insert a new item
|
||||
startActivity(new Intent(Intent.INSERT_ACTION, getIntent().getData()))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (C) 2007 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.android.notepad
|
||||
|
||||
import com.google.provider.NotePad
|
||||
|
||||
import _root_.android.app.Activity
|
||||
import _root_.android.database.Cursor
|
||||
import _root_.android.net.ContentURI
|
||||
import _root_.android.os.Bundle
|
||||
import _root_.android.view.View
|
||||
import _root_.android.widget.{Button, EditText}
|
||||
|
||||
|
||||
/**
|
||||
* An activity that will edit the title of a note. Displays a floating
|
||||
* window with a text field.
|
||||
*/
|
||||
object TitleEditor {
|
||||
|
||||
/**
|
||||
* This is a special intent action that means "edit the title of a note".
|
||||
*/
|
||||
val EDIT_TITLE_ACTION =
|
||||
"com.google.android.notepad.action.EDIT_TITLE"
|
||||
|
||||
/**
|
||||
* Index of the title column
|
||||
*/
|
||||
private val TITLE_INDEX = 1
|
||||
|
||||
/**
|
||||
* An array of the columns we are interested in.
|
||||
*/
|
||||
private val PROJECTION = Array(
|
||||
NotePad.Notes._ID, // 0
|
||||
NotePad.Notes.TITLE, // 1
|
||||
)
|
||||
}
|
||||
|
||||
class TitleEditor extends Activity with View.OnClickListener {
|
||||
import TitleEditor._ // companion object
|
||||
|
||||
/**
|
||||
* Cursor which will provide access to the note whose title we are editing.
|
||||
*/
|
||||
var mCursor: Cursor = _
|
||||
|
||||
/**
|
||||
* The EditText field from our UI. Keep track of this so we can extract the
|
||||
* text when we are finished.
|
||||
*/
|
||||
var mText: EditText = _
|
||||
|
||||
override def onCreate(icicle: Bundle) {
|
||||
super.onCreate(icicle)
|
||||
|
||||
setContentView(R.layout.title_editor)
|
||||
|
||||
// Get the uri of the note whose title we want to edit
|
||||
val uri = getIntent().getData()
|
||||
|
||||
// Get a cursor to access the note
|
||||
mCursor = managedQuery(uri, PROJECTION, null, null)
|
||||
|
||||
// Set up click handlers for the text field and button
|
||||
mText = this.findViewById(R.id.title).asInstanceOf[EditText]
|
||||
mText setOnClickListener this
|
||||
|
||||
val b = /*(Button)*/ findViewById(R.id.ok)
|
||||
b setOnClickListener this
|
||||
}
|
||||
|
||||
override protected def onResume() {
|
||||
super.onResume()
|
||||
|
||||
// Initialize the text with the title column from the cursor
|
||||
if (mCursor != null) {
|
||||
mCursor.first()
|
||||
val title = mCursor getString TITLE_INDEX
|
||||
mText setText title
|
||||
}
|
||||
}
|
||||
|
||||
override protected def onPause() {
|
||||
super.onPause()
|
||||
|
||||
// Write the text back into the cursor
|
||||
if (mCursor != null) {
|
||||
val title = mText.getText().toString()
|
||||
mCursor.updateString(TITLE_INDEX, title)
|
||||
mCursor.commitUpdates()
|
||||
}
|
||||
}
|
||||
|
||||
def onClick(v: View) {
|
||||
// When the user clicks, just finish this activity.
|
||||
// onPause will be called, and we save our data there.
|
||||
finish()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (C) 2007 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.provider
|
||||
|
||||
import _root_.android.net.ContentURI
|
||||
import _root_.android.provider.BaseColumns
|
||||
|
||||
/**
|
||||
* Convenience definitions for NotePadProvider
|
||||
*/
|
||||
object NotePad {
|
||||
/**
|
||||
* Notes table
|
||||
*/
|
||||
object Notes {
|
||||
|
||||
val _ID = BaseColumns._ID
|
||||
|
||||
val _COUNT = BaseColumns._COUNT
|
||||
/**
|
||||
* The content:// style URL for this table
|
||||
*/
|
||||
val CONTENT_URI =
|
||||
ContentURI.create("content://com.google.provider.NotePad/notes")
|
||||
|
||||
/**
|
||||
* The default sort order for this table
|
||||
*/
|
||||
val DEFAULT_SORT_ORDER = "modified DESC"
|
||||
|
||||
/**
|
||||
* The title of the note
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
val TITLE = "title"
|
||||
|
||||
/**
|
||||
* The note itself
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
val NOTE = "note"
|
||||
|
||||
/**
|
||||
* The timestamp for when the note was created
|
||||
* <P>Type: INTEGER (long)</P>
|
||||
*/
|
||||
val CREATED_DATE = "created"
|
||||
|
||||
/**
|
||||
* The timestamp for when the note was last modified
|
||||
* <P>Type: INTEGER (long)</P>
|
||||
*/
|
||||
val MODIFIED_DATE = "modified"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue