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"
|
basedir="${android.dir}/lib/library"
|
||||||
includes="scala/**/*.class"
|
includes="scala/**/*.class"
|
||||||
/>
|
/>
|
||||||
<!-- examples ? -->
|
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<target name="android" depends="init">
|
<target name="android" depends="init">
|
||||||
|
@ -1827,6 +1826,11 @@ GENERATES A DISTRIBUTION
|
||||||
</quicksbaz>
|
</quicksbaz>
|
||||||
<!-- Creates the Android package -->
|
<!-- Creates the Android package -->
|
||||||
<if><isset property="android.supported"/><then>
|
<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
|
<quicksbaz
|
||||||
file="${dist.dir}/scala-android-${version.number}.sbp"
|
file="${dist.dir}/scala-android-${version.number}.sbp"
|
||||||
adfile="${dist.dir}/scala-android-${version.number}.advert"
|
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."
|
desc="The Scala Android package contains everything needed to use Scala on Android."
|
||||||
link="${sbaz.universe}/scala-android-${version.number}.sbp">
|
link="${sbaz.universe}/scala-android-${version.number}.sbp">
|
||||||
<libset dir="${android.dir}/lib" includes="*.jar"/>
|
<libset dir="${android.dir}/lib" includes="*.jar"/>
|
||||||
|
<docset dir="${dist.current.dir}/doc/scala-android" includes="**"/>
|
||||||
</quicksbaz>
|
</quicksbaz>
|
||||||
</then></if>
|
</then></if>
|
||||||
</target>
|
</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