diff --git a/samples/AccelerometerPlay/_index.jd b/samples/AccelerometerPlay/_index.jd
index cdca3a6b1..488cda777 100644
--- a/samples/AccelerometerPlay/_index.jd
+++ b/samples/AccelerometerPlay/_index.jd
@@ -1,3 +1,4 @@
+page.keywords="Sensor", "Games", "Accelerometer"
page.tags="Sensor", "Games", "Accelerometer"
sample.group=Sensors
@jd:body
diff --git a/samples/browseable/ActivityInstrumentation/AndroidManifest.xml b/samples/browseable/ActivityInstrumentation/AndroidManifest.xml
new file mode 100644
index 000000000..547d95ee7
--- /dev/null
+++ b/samples/browseable/ActivityInstrumentation/AndroidManifest.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+ + This sample provides a basic example of using an InstrumentationTest to probe the + internal state of an Activity. + +
diff --git a/samples/browseable/ActivityInstrumentation/res/drawable-hdpi/ic_launcher.png b/samples/browseable/ActivityInstrumentation/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..b1efaf4b2 Binary files /dev/null and b/samples/browseable/ActivityInstrumentation/res/drawable-hdpi/ic_launcher.png differ diff --git a/samples/browseable/ActivityInstrumentation/res/drawable-hdpi/tile.9.png b/samples/browseable/ActivityInstrumentation/res/drawable-hdpi/tile.9.png new file mode 100644 index 000000000..135862883 Binary files /dev/null and b/samples/browseable/ActivityInstrumentation/res/drawable-hdpi/tile.9.png differ diff --git a/samples/browseable/ActivityInstrumentation/res/drawable-mdpi/ic_launcher.png b/samples/browseable/ActivityInstrumentation/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..f5f9244f2 Binary files /dev/null and b/samples/browseable/ActivityInstrumentation/res/drawable-mdpi/ic_launcher.png differ diff --git a/samples/browseable/ActivityInstrumentation/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/ActivityInstrumentation/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..5d07b3f06 Binary files /dev/null and b/samples/browseable/ActivityInstrumentation/res/drawable-xhdpi/ic_launcher.png differ diff --git a/samples/browseable/ActivityInstrumentation/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/ActivityInstrumentation/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..6ef21e1f4 Binary files /dev/null and b/samples/browseable/ActivityInstrumentation/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/samples/browseable/ActivityInstrumentation/res/layout/activity_main.xml b/samples/browseable/ActivityInstrumentation/res/layout/activity_main.xml new file mode 100755 index 000000000..be1aa49d9 --- /dev/null +++ b/samples/browseable/ActivityInstrumentation/res/layout/activity_main.xml @@ -0,0 +1,36 @@ + + +When this is set as the head of the list, + * an instance of it can function as a drop-in replacement for {@link android.util.Log}. + * Most of the methods in this class server only to map a method call in Log to its equivalent + * in LogNode.
+ */ +public class Log { + // Grabbing the native values from Android's native logging facilities, + // to make for easy migration and interop. + public static final int NONE = -1; + public static final int VERBOSE = android.util.Log.VERBOSE; + public static final int DEBUG = android.util.Log.DEBUG; + public static final int INFO = android.util.Log.INFO; + public static final int WARN = android.util.Log.WARN; + public static final int ERROR = android.util.Log.ERROR; + public static final int ASSERT = android.util.Log.ASSERT; + + // Stores the beginning of the LogNode topology. + private static LogNode mLogNode; + + /** + * Returns the next LogNode in the linked list. + */ + public static LogNode getLogNode() { + return mLogNode; + } + + /** + * Sets the LogNode data will be sent to. + */ + public static void setLogNode(LogNode node) { + mLogNode = node; + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void println(int priority, String tag, String msg, Throwable tr) { + if (mLogNode != null) { + mLogNode.println(priority, tag, msg, tr); + } + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + */ + public static void println(int priority, String tag, String msg) { + println(priority, tag, msg, null); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void v(String tag, String msg, Throwable tr) { + println(VERBOSE, tag, msg, tr); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void v(String tag, String msg) { + v(tag, msg, null); + } + + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void d(String tag, String msg, Throwable tr) { + println(DEBUG, tag, msg, tr); + } + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void d(String tag, String msg) { + d(tag, msg, null); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void i(String tag, String msg, Throwable tr) { + println(INFO, tag, msg, tr); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void i(String tag, String msg) { + i(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, String msg, Throwable tr) { + println(WARN, tag, msg, tr); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void w(String tag, String msg) { + w(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, Throwable tr) { + w(tag, null, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void e(String tag, String msg, Throwable tr) { + println(ERROR, tag, msg, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void e(String tag, String msg) { + e(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, String msg, Throwable tr) { + println(ASSERT, tag, msg, tr); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void wtf(String tag, String msg) { + wtf(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, Throwable tr) { + wtf(tag, null, tr); + } +} diff --git a/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogFragment.java new file mode 100644 index 000000000..b302acd4b --- /dev/null +++ b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogFragment.java @@ -0,0 +1,109 @@ +/* +* Copyright 2013 The Android Open Source Project +* +* 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. +*/ +/* + * Copyright 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ScrollView; + +/** + * Simple fraggment which contains a LogView and uses is to output log data it receives + * through the LogNode interface. + */ +public class LogFragment extends Fragment { + + private LogView mLogView; + private ScrollView mScrollView; + + public LogFragment() {} + + public View inflateViews() { + mScrollView = new ScrollView(getActivity()); + ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mScrollView.setLayoutParams(scrollParams); + + mLogView = new LogView(getActivity()); + ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams); + logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + mLogView.setLayoutParams(logParams); + mLogView.setClickable(true); + mLogView.setFocusable(true); + mLogView.setTypeface(Typeface.MONOSPACE); + + // Want to set padding as 16 dips, setPadding takes pixels. Hooray math! + int paddingDips = 16; + double scale = getResources().getDisplayMetrics().density; + int paddingPixels = (int) ((paddingDips * (scale)) + .5); + mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels); + mLogView.setCompoundDrawablePadding(paddingPixels); + + mLogView.setGravity(Gravity.BOTTOM); + mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium); + + mScrollView.addView(mLogView); + return mScrollView; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View result = inflateViews(); + + mLogView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + mScrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + }); + return result; + } + + public LogView getLogView() { + return mLogView; + } +} \ No newline at end of file diff --git a/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogNode.java b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogNode.java new file mode 100644 index 000000000..bc37cabc0 --- /dev/null +++ b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogNode.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Basic interface for a logging system that can output to one or more targets. + * Note that in addition to classes that will output these logs in some format, + * one can also implement this interface over a filter and insert that in the chain, + * such that no targets further down see certain data, or see manipulated forms of the data. + * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data + * it received to HTML and sent it along to the next node in the chain, without printing it + * anywhere. + */ +public interface LogNode { + + /** + * Instructs first LogNode in the list to print the log data provided. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public void println(int priority, String tag, String msg, Throwable tr); + +} diff --git a/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogView.java b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogView.java new file mode 100644 index 000000000..c01542b91 --- /dev/null +++ b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogView.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.app.Activity; +import android.content.Context; +import android.util.*; +import android.widget.TextView; + +/** Simple TextView which is used to output log data received through the LogNode interface. +*/ +public class LogView extends TextView implements LogNode { + + public LogView(Context context) { + super(context); + } + + public LogView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LogView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Formats the log data and prints it out to the LogView. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + + + String priorityStr = null; + + // For the purposes of this View, we want to print the priority as readable text. + switch(priority) { + case android.util.Log.VERBOSE: + priorityStr = "VERBOSE"; + break; + case android.util.Log.DEBUG: + priorityStr = "DEBUG"; + break; + case android.util.Log.INFO: + priorityStr = "INFO"; + break; + case android.util.Log.WARN: + priorityStr = "WARN"; + break; + case android.util.Log.ERROR: + priorityStr = "ERROR"; + break; + case android.util.Log.ASSERT: + priorityStr = "ASSERT"; + break; + default: + break; + } + + // Handily, the Log class has a facility for converting a stack trace into a usable string. + String exceptionStr = null; + if (tr != null) { + exceptionStr = android.util.Log.getStackTraceString(tr); + } + + // Take the priority, tag, message, and exception, and concatenate as necessary + // into one usable line of text. + final StringBuilder outputBuilder = new StringBuilder(); + + String delimiter = "\t"; + appendIfNotNull(outputBuilder, priorityStr, delimiter); + appendIfNotNull(outputBuilder, tag, delimiter); + appendIfNotNull(outputBuilder, msg, delimiter); + appendIfNotNull(outputBuilder, exceptionStr, delimiter); + + // In case this was originally called from an AsyncTask or some other off-UI thread, + // make sure the update occurs within the UI thread. + ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() { + @Override + public void run() { + // Display the text we just generated within the LogView. + appendToLog(outputBuilder.toString()); + } + }))); + + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } + + public LogNode getNext() { + return mNext; + } + + public void setNext(LogNode node) { + mNext = node; + } + + /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since + * the logger takes so many arguments that might be null, this method helps cut out some of the + * agonizing tedium of writing the same 3 lines over and over. + * @param source StringBuilder containing the text to append to. + * @param addStr The String to append + * @param delimiter The String to separate the source and appended strings. A tab or comma, + * for instance. + * @return The fully concatenated String as a StringBuilder + */ + private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) { + if (addStr != null) { + if (addStr.length() == 0) { + delimiter = ""; + } + + return source.append(addStr).append(delimiter); + } + return source; + } + + // The next LogNode in the chain. + LogNode mNext; + + /** Outputs the string as a new line of log data in the LogView. */ + public void appendToLog(String s) { + append("\n" + s); + } + + +} diff --git a/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogWrapper.java new file mode 100644 index 000000000..16a9e7ba2 --- /dev/null +++ b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/LogWrapper.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.util.Log; + +/** + * Helper class which wraps Android's native Log utility in the Logger interface. This way + * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously. + */ +public class LogWrapper implements LogNode { + + // For piping: The next node to receive Log data after this one has done its work. + private LogNode mNext; + + /** + * Returns the next LogNode in the linked list. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + + /** + * Prints data out to the console using Android's native log mechanism. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + // There actually are log methods that don't take a msg parameter. For now, + // if that's the case, just convert null to the empty string and move on. + String useMsg = msg; + if (useMsg == null) { + useMsg = ""; + } + + // If an exeption was provided, convert that exception to a usable string and attach + // it to the end of the msg method. + if (tr != null) { + msg += "\n" + Log.getStackTraceString(tr); + } + + // This is functionally identical to Log.x(tag, useMsg); + // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg) + Log.println(priority, tag, useMsg); + + // If this isn't the last node in the chain, move things along. + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } +} diff --git a/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/MessageOnlyLogFilter.java new file mode 100644 index 000000000..19967dcd4 --- /dev/null +++ b/samples/browseable/ActivityInstrumentation/src/com.example.android.common.logger/MessageOnlyLogFilter.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Simple {@link LogNode} filter, removes everything except the message. + * Useful for situations like on-screen log output where you don't want a lot of metadata displayed, + * just easy-to-read message updates as they're happening. + */ +public class MessageOnlyLogFilter implements LogNode { + + LogNode mNext; + + /** + * Takes the "next" LogNode as a parameter, to simplify chaining. + * + * @param next The next LogNode in the pipeline. + */ + public MessageOnlyLogFilter(LogNode next) { + mNext = next; + } + + public MessageOnlyLogFilter() { + } + + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + if (mNext != null) { + getNext().println(Log.NONE, null, msg, null); + } + } + + /** + * Returns the next LogNode in the chain. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + +} diff --git a/samples/browseable/AdvancedImmersiveMode/AndroidManifest.xml b/samples/browseable/AdvancedImmersiveMode/AndroidManifest.xml new file mode 100644 index 000000000..1d01856c8 --- /dev/null +++ b/samples/browseable/AdvancedImmersiveMode/AndroidManifest.xml @@ -0,0 +1,56 @@ + + + + ++ + \"Immersive Mode\" is a new UI mode which improves \"hide full screen\" and + \"hide nav bar\" modes, by letting users swipe the bars in and out. This sample + lets the user experiment with immersive mode by enabling it and seeing how it interacts + with some of the other UI flags related to full-screen apps. + \n\nThis sample also lets the user choose between normal immersive mode and "sticky" + immersive mode, which removes the status bar and nav bar + a few seconds after the user has swiped them back in. + +
diff --git a/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/ic_launcher.png b/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..b1efaf4b2 Binary files /dev/null and b/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/ic_launcher.png differ diff --git a/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/tile.9.png b/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/tile.9.png new file mode 100644 index 000000000..135862883 Binary files /dev/null and b/samples/browseable/AdvancedImmersiveMode/res/drawable-hdpi/tile.9.png differ diff --git a/samples/browseable/AdvancedImmersiveMode/res/drawable-mdpi/ic_launcher.png b/samples/browseable/AdvancedImmersiveMode/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..f5f9244f2 Binary files /dev/null and b/samples/browseable/AdvancedImmersiveMode/res/drawable-mdpi/ic_launcher.png differ diff --git a/samples/browseable/AdvancedImmersiveMode/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/AdvancedImmersiveMode/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..5d07b3f06 Binary files /dev/null and b/samples/browseable/AdvancedImmersiveMode/res/drawable-xhdpi/ic_launcher.png differ diff --git a/samples/browseable/AdvancedImmersiveMode/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/AdvancedImmersiveMode/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..6ef21e1f4 Binary files /dev/null and b/samples/browseable/AdvancedImmersiveMode/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/samples/browseable/AdvancedImmersiveMode/res/layout/activity_main.xml b/samples/browseable/AdvancedImmersiveMode/res/layout/activity_main.xml new file mode 100755 index 000000000..bc5a57591 --- /dev/null +++ b/samples/browseable/AdvancedImmersiveMode/res/layout/activity_main.xml @@ -0,0 +1,38 @@ + +When this is set as the head of the list, + * an instance of it can function as a drop-in replacement for {@link android.util.Log}. + * Most of the methods in this class server only to map a method call in Log to its equivalent + * in LogNode.
+ */ +public class Log { + // Grabbing the native values from Android's native logging facilities, + // to make for easy migration and interop. + public static final int NONE = -1; + public static final int VERBOSE = android.util.Log.VERBOSE; + public static final int DEBUG = android.util.Log.DEBUG; + public static final int INFO = android.util.Log.INFO; + public static final int WARN = android.util.Log.WARN; + public static final int ERROR = android.util.Log.ERROR; + public static final int ASSERT = android.util.Log.ASSERT; + + // Stores the beginning of the LogNode topology. + private static LogNode mLogNode; + + /** + * Returns the next LogNode in the linked list. + */ + public static LogNode getLogNode() { + return mLogNode; + } + + /** + * Sets the LogNode data will be sent to. + */ + public static void setLogNode(LogNode node) { + mLogNode = node; + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void println(int priority, String tag, String msg, Throwable tr) { + if (mLogNode != null) { + mLogNode.println(priority, tag, msg, tr); + } + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + */ + public static void println(int priority, String tag, String msg) { + println(priority, tag, msg, null); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void v(String tag, String msg, Throwable tr) { + println(VERBOSE, tag, msg, tr); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void v(String tag, String msg) { + v(tag, msg, null); + } + + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void d(String tag, String msg, Throwable tr) { + println(DEBUG, tag, msg, tr); + } + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void d(String tag, String msg) { + d(tag, msg, null); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void i(String tag, String msg, Throwable tr) { + println(INFO, tag, msg, tr); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void i(String tag, String msg) { + i(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, String msg, Throwable tr) { + println(WARN, tag, msg, tr); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void w(String tag, String msg) { + w(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, Throwable tr) { + w(tag, null, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void e(String tag, String msg, Throwable tr) { + println(ERROR, tag, msg, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void e(String tag, String msg) { + e(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, String msg, Throwable tr) { + println(ASSERT, tag, msg, tr); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void wtf(String tag, String msg) { + wtf(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, Throwable tr) { + wtf(tag, null, tr); + } +} diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogFragment.java new file mode 100644 index 000000000..b302acd4b --- /dev/null +++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogFragment.java @@ -0,0 +1,109 @@ +/* +* Copyright 2013 The Android Open Source Project +* +* 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. +*/ +/* + * Copyright 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ScrollView; + +/** + * Simple fraggment which contains a LogView and uses is to output log data it receives + * through the LogNode interface. + */ +public class LogFragment extends Fragment { + + private LogView mLogView; + private ScrollView mScrollView; + + public LogFragment() {} + + public View inflateViews() { + mScrollView = new ScrollView(getActivity()); + ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mScrollView.setLayoutParams(scrollParams); + + mLogView = new LogView(getActivity()); + ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams); + logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + mLogView.setLayoutParams(logParams); + mLogView.setClickable(true); + mLogView.setFocusable(true); + mLogView.setTypeface(Typeface.MONOSPACE); + + // Want to set padding as 16 dips, setPadding takes pixels. Hooray math! + int paddingDips = 16; + double scale = getResources().getDisplayMetrics().density; + int paddingPixels = (int) ((paddingDips * (scale)) + .5); + mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels); + mLogView.setCompoundDrawablePadding(paddingPixels); + + mLogView.setGravity(Gravity.BOTTOM); + mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium); + + mScrollView.addView(mLogView); + return mScrollView; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View result = inflateViews(); + + mLogView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + mScrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + }); + return result; + } + + public LogView getLogView() { + return mLogView; + } +} \ No newline at end of file diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogNode.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogNode.java new file mode 100644 index 000000000..bc37cabc0 --- /dev/null +++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogNode.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Basic interface for a logging system that can output to one or more targets. + * Note that in addition to classes that will output these logs in some format, + * one can also implement this interface over a filter and insert that in the chain, + * such that no targets further down see certain data, or see manipulated forms of the data. + * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data + * it received to HTML and sent it along to the next node in the chain, without printing it + * anywhere. + */ +public interface LogNode { + + /** + * Instructs first LogNode in the list to print the log data provided. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public void println(int priority, String tag, String msg, Throwable tr); + +} diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogView.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogView.java new file mode 100644 index 000000000..c01542b91 --- /dev/null +++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogView.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.app.Activity; +import android.content.Context; +import android.util.*; +import android.widget.TextView; + +/** Simple TextView which is used to output log data received through the LogNode interface. +*/ +public class LogView extends TextView implements LogNode { + + public LogView(Context context) { + super(context); + } + + public LogView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LogView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Formats the log data and prints it out to the LogView. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + + + String priorityStr = null; + + // For the purposes of this View, we want to print the priority as readable text. + switch(priority) { + case android.util.Log.VERBOSE: + priorityStr = "VERBOSE"; + break; + case android.util.Log.DEBUG: + priorityStr = "DEBUG"; + break; + case android.util.Log.INFO: + priorityStr = "INFO"; + break; + case android.util.Log.WARN: + priorityStr = "WARN"; + break; + case android.util.Log.ERROR: + priorityStr = "ERROR"; + break; + case android.util.Log.ASSERT: + priorityStr = "ASSERT"; + break; + default: + break; + } + + // Handily, the Log class has a facility for converting a stack trace into a usable string. + String exceptionStr = null; + if (tr != null) { + exceptionStr = android.util.Log.getStackTraceString(tr); + } + + // Take the priority, tag, message, and exception, and concatenate as necessary + // into one usable line of text. + final StringBuilder outputBuilder = new StringBuilder(); + + String delimiter = "\t"; + appendIfNotNull(outputBuilder, priorityStr, delimiter); + appendIfNotNull(outputBuilder, tag, delimiter); + appendIfNotNull(outputBuilder, msg, delimiter); + appendIfNotNull(outputBuilder, exceptionStr, delimiter); + + // In case this was originally called from an AsyncTask or some other off-UI thread, + // make sure the update occurs within the UI thread. + ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() { + @Override + public void run() { + // Display the text we just generated within the LogView. + appendToLog(outputBuilder.toString()); + } + }))); + + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } + + public LogNode getNext() { + return mNext; + } + + public void setNext(LogNode node) { + mNext = node; + } + + /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since + * the logger takes so many arguments that might be null, this method helps cut out some of the + * agonizing tedium of writing the same 3 lines over and over. + * @param source StringBuilder containing the text to append to. + * @param addStr The String to append + * @param delimiter The String to separate the source and appended strings. A tab or comma, + * for instance. + * @return The fully concatenated String as a StringBuilder + */ + private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) { + if (addStr != null) { + if (addStr.length() == 0) { + delimiter = ""; + } + + return source.append(addStr).append(delimiter); + } + return source; + } + + // The next LogNode in the chain. + LogNode mNext; + + /** Outputs the string as a new line of log data in the LogView. */ + public void appendToLog(String s) { + append("\n" + s); + } + + +} diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogWrapper.java new file mode 100644 index 000000000..16a9e7ba2 --- /dev/null +++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/LogWrapper.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.util.Log; + +/** + * Helper class which wraps Android's native Log utility in the Logger interface. This way + * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously. + */ +public class LogWrapper implements LogNode { + + // For piping: The next node to receive Log data after this one has done its work. + private LogNode mNext; + + /** + * Returns the next LogNode in the linked list. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + + /** + * Prints data out to the console using Android's native log mechanism. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + // There actually are log methods that don't take a msg parameter. For now, + // if that's the case, just convert null to the empty string and move on. + String useMsg = msg; + if (useMsg == null) { + useMsg = ""; + } + + // If an exeption was provided, convert that exception to a usable string and attach + // it to the end of the msg method. + if (tr != null) { + msg += "\n" + Log.getStackTraceString(tr); + } + + // This is functionally identical to Log.x(tag, useMsg); + // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg) + Log.println(priority, tag, useMsg); + + // If this isn't the last node in the chain, move things along. + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } +} diff --git a/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.java new file mode 100644 index 000000000..19967dcd4 --- /dev/null +++ b/samples/browseable/AdvancedImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Simple {@link LogNode} filter, removes everything except the message. + * Useful for situations like on-screen log output where you don't want a lot of metadata displayed, + * just easy-to-read message updates as they're happening. + */ +public class MessageOnlyLogFilter implements LogNode { + + LogNode mNext; + + /** + * Takes the "next" LogNode as a parameter, to simplify chaining. + * + * @param next The next LogNode in the pipeline. + */ + public MessageOnlyLogFilter(LogNode next) { + mNext = next; + } + + public MessageOnlyLogFilter() { + } + + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + if (mNext != null) { + getNext().println(Log.NONE, null, msg, null); + } + } + + /** + * Returns the next LogNode in the chain. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + +} diff --git a/samples/browseable/AppRestrictions/AndroidManifest.xml b/samples/browseable/AppRestrictions/AndroidManifest.xml new file mode 100644 index 000000000..b492bbfce --- /dev/null +++ b/samples/browseable/AppRestrictions/AndroidManifest.xml @@ -0,0 +1,48 @@ + + + + + ++ + This sample demonstrates the use of the App Restriction feature, which is available on + Android 4.3 and above tablet device with the multiuser feature. + + When launched under the primary User account, you can toggle between standard app restriction + types and custom. When launched under a restricted profile, this activity displays app + restriction settings, if available. + +
diff --git a/samples/browseable/AppRestrictions/res/drawable-hdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/drawable-hdpi/ic_launcher.png new file mode 100755 index 000000000..f36c473a1 Binary files /dev/null and b/samples/browseable/AppRestrictions/res/drawable-hdpi/ic_launcher.png differ diff --git a/samples/browseable/AppRestrictions/res/drawable-hdpi/tile.9.png b/samples/browseable/AppRestrictions/res/drawable-hdpi/tile.9.png new file mode 100644 index 000000000..135862883 Binary files /dev/null and b/samples/browseable/AppRestrictions/res/drawable-hdpi/tile.9.png differ diff --git a/samples/browseable/AppRestrictions/res/drawable-mdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/drawable-mdpi/ic_launcher.png new file mode 100755 index 000000000..5ab2e0d33 Binary files /dev/null and b/samples/browseable/AppRestrictions/res/drawable-mdpi/ic_launcher.png differ diff --git a/samples/browseable/AppRestrictions/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/drawable-xhdpi/ic_launcher.png new file mode 100755 index 000000000..76228388e Binary files /dev/null and b/samples/browseable/AppRestrictions/res/drawable-xhdpi/ic_launcher.png differ diff --git a/samples/browseable/AppRestrictions/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/AppRestrictions/res/drawable-xxhdpi/ic_launcher.png new file mode 100755 index 000000000..7f55feff2 Binary files /dev/null and b/samples/browseable/AppRestrictions/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/samples/browseable/AppRestrictions/res/layout/activity_main.xml b/samples/browseable/AppRestrictions/res/layout/activity_main.xml new file mode 100755 index 000000000..be1aa49d9 --- /dev/null +++ b/samples/browseable/AppRestrictions/res/layout/activity_main.xml @@ -0,0 +1,36 @@ + + ++ + This sample shows you how to use ActionBarCompat to create a basic Activity which + displays action items. It covers inflating items from a menu resource, as well as adding + an item in code. Items that are not shown as action items on the Action Bar are + displayed in the action bar overflow. + +
diff --git a/samples/browseable/Basic/res/drawable-hdpi/ic_action_location.png b/samples/browseable/Basic/res/drawable-hdpi/ic_action_location.png new file mode 100644 index 000000000..a42b3ea9f Binary files /dev/null and b/samples/browseable/Basic/res/drawable-hdpi/ic_action_location.png differ diff --git a/samples/browseable/Basic/res/drawable-hdpi/ic_action_refresh.png b/samples/browseable/Basic/res/drawable-hdpi/ic_action_refresh.png new file mode 100644 index 000000000..c9d295d6b Binary files /dev/null and b/samples/browseable/Basic/res/drawable-hdpi/ic_action_refresh.png differ diff --git a/samples/browseable/Basic/res/drawable-hdpi/ic_action_settings.png b/samples/browseable/Basic/res/drawable-hdpi/ic_action_settings.png new file mode 100644 index 000000000..d3f981d09 Binary files /dev/null and b/samples/browseable/Basic/res/drawable-hdpi/ic_action_settings.png differ diff --git a/samples/browseable/Basic/res/drawable-hdpi/ic_launcher.png b/samples/browseable/Basic/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..5bb19fbe8 Binary files /dev/null and b/samples/browseable/Basic/res/drawable-hdpi/ic_launcher.png differ diff --git a/samples/browseable/Basic/res/drawable-hdpi/tile.9.png b/samples/browseable/Basic/res/drawable-hdpi/tile.9.png new file mode 100644 index 000000000..135862883 Binary files /dev/null and b/samples/browseable/Basic/res/drawable-hdpi/tile.9.png differ diff --git a/samples/browseable/Basic/res/drawable-mdpi/ic_action_location.png b/samples/browseable/Basic/res/drawable-mdpi/ic_action_location.png new file mode 100644 index 000000000..eaf97745c Binary files /dev/null and b/samples/browseable/Basic/res/drawable-mdpi/ic_action_location.png differ diff --git a/samples/browseable/Basic/res/drawable-mdpi/ic_action_refresh.png b/samples/browseable/Basic/res/drawable-mdpi/ic_action_refresh.png new file mode 100644 index 000000000..eef97e9ec Binary files /dev/null and b/samples/browseable/Basic/res/drawable-mdpi/ic_action_refresh.png differ diff --git a/samples/browseable/Basic/res/drawable-mdpi/ic_action_settings.png b/samples/browseable/Basic/res/drawable-mdpi/ic_action_settings.png new file mode 100644 index 000000000..fc2bf8c39 Binary files /dev/null and b/samples/browseable/Basic/res/drawable-mdpi/ic_action_settings.png differ diff --git a/samples/browseable/Basic/res/drawable-mdpi/ic_launcher.png b/samples/browseable/Basic/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..5737b3631 Binary files /dev/null and b/samples/browseable/Basic/res/drawable-mdpi/ic_launcher.png differ diff --git a/samples/browseable/Basic/res/drawable-xhdpi/ic_action_location.png b/samples/browseable/Basic/res/drawable-xhdpi/ic_action_location.png new file mode 100644 index 000000000..5f11cce1b Binary files /dev/null and b/samples/browseable/Basic/res/drawable-xhdpi/ic_action_location.png differ diff --git a/samples/browseable/Basic/res/drawable-xhdpi/ic_action_refresh.png b/samples/browseable/Basic/res/drawable-xhdpi/ic_action_refresh.png new file mode 100644 index 000000000..1027c9a47 Binary files /dev/null and b/samples/browseable/Basic/res/drawable-xhdpi/ic_action_refresh.png differ diff --git a/samples/browseable/Basic/res/drawable-xhdpi/ic_action_settings.png b/samples/browseable/Basic/res/drawable-xhdpi/ic_action_settings.png new file mode 100644 index 000000000..1b9acf26d Binary files /dev/null and b/samples/browseable/Basic/res/drawable-xhdpi/ic_action_settings.png differ diff --git a/samples/browseable/Basic/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/Basic/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..31df0432a Binary files /dev/null and b/samples/browseable/Basic/res/drawable-xhdpi/ic_launcher.png differ diff --git a/samples/browseable/Basic/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/Basic/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..508743576 Binary files /dev/null and b/samples/browseable/Basic/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/samples/browseable/Basic/res/layout/activity_main.xml b/samples/browseable/Basic/res/layout/activity_main.xml new file mode 100755 index 000000000..be1aa49d9 --- /dev/null +++ b/samples/browseable/Basic/res/layout/activity_main.xml @@ -0,0 +1,36 @@ + + ++ + This sample demonstrates how to create an accessible application, using a mix of different widgets demonstrating different ways of adding accessibility markup to a UI. + +
diff --git a/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_action_discard.png b/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_action_discard.png new file mode 100644 index 000000000..ece5ad8d6 Binary files /dev/null and b/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_action_discard.png differ diff --git a/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_action_info.png b/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_action_info.png new file mode 100644 index 000000000..da65dea1d Binary files /dev/null and b/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_action_info.png differ diff --git a/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..6c0b5ee4e Binary files /dev/null and b/samples/browseable/BasicAccessibility/res/drawable-hdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicAccessibility/res/drawable-hdpi/partly_cloudy.png b/samples/browseable/BasicAccessibility/res/drawable-hdpi/partly_cloudy.png new file mode 100644 index 000000000..b1b380c96 Binary files /dev/null and b/samples/browseable/BasicAccessibility/res/drawable-hdpi/partly_cloudy.png differ diff --git a/samples/browseable/BasicAccessibility/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicAccessibility/res/drawable-hdpi/tile.9.png new file mode 100644 index 000000000..135862883 Binary files /dev/null and b/samples/browseable/BasicAccessibility/res/drawable-hdpi/tile.9.png differ diff --git a/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_action_discard.png b/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_action_discard.png new file mode 100644 index 000000000..93483b6cb Binary files /dev/null and b/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_action_discard.png differ diff --git a/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_action_info.png b/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_action_info.png new file mode 100644 index 000000000..7f7e0a3dc Binary files /dev/null and b/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_action_info.png differ diff --git a/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..4ce0b8226 Binary files /dev/null and b/samples/browseable/BasicAccessibility/res/drawable-mdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_action_discard.png b/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_action_discard.png new file mode 100644 index 000000000..94f7c8c1c Binary files /dev/null and b/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_action_discard.png differ diff --git a/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_action_info.png b/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_action_info.png new file mode 100644 index 000000000..4ede9ce3f Binary files /dev/null and b/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_action_info.png differ diff --git a/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..6ded70731 Binary files /dev/null and b/samples/browseable/BasicAccessibility/res/drawable-xhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicAccessibility/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicAccessibility/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..74ae891e3 Binary files /dev/null and b/samples/browseable/BasicAccessibility/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicAccessibility/res/layout/activity_main.xml b/samples/browseable/BasicAccessibility/res/layout/activity_main.xml new file mode 100755 index 000000000..be1aa49d9 --- /dev/null +++ b/samples/browseable/BasicAccessibility/res/layout/activity_main.xml @@ -0,0 +1,36 @@ + + +This view does not use any framework widgets, so does not get any accessibility features + * automatically. Instead, we use {@link android.view.accessibility.AccessibilityEvent} to provide accessibility hints to + * the OS. + * + *
For example, if TalkBack is enabled, users will be able to receive spoken feedback as they + * interact with this view. + * + *
More generally, this view renders a multi-position "dial" that can be used to select a value + * between 1 and 4. Each time the dial is clicked, the next position will be selected (modulo + * the maximum number of positions). + */ +public class DialView extends View { + private static int SELECTION_COUNT = 4; + + private static float FONT_SIZE = 40f; + private float mWidth; + private float mHeight; + private float mWidthPadded; + private float mHeightPadded; + private Paint mTextPaint; + private Paint mDialPaint; + private float mRadius; + private int mActiveSelection; + + /** + * Constructor that is called when inflating a view from XML. This is called + * when a view is being constructed from an XML file, supplying attributes + * that were specified in the XML file. + * + *
In our case, this constructor just calls init(). + * + * @param context The Context the view is running in, through which it can + * access the current theme, resources, etc. + * @param attrs The attributes of the XML tag that is inflating the view. + * @see #View(android.content.Context, android.util.AttributeSet, int) + */ + public DialView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + /** + * Helper method to initialize instance variables. Called by constructor. + */ + private void init() { + // Paint styles used for rendering are created here, rather than at render-time. This + // is a performance optimization, since onDraw() will get called frequently. + mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mTextPaint.setColor(Color.BLACK); + mTextPaint.setStyle(Paint.Style.FILL_AND_STROKE); + mTextPaint.setTextAlign(Paint.Align.CENTER); + mTextPaint.setTextSize(FONT_SIZE); + + mDialPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mDialPaint.setColor(Color.GRAY); + + // Initialize current selection. This will store where the dial's "indicator" is pointing. + mActiveSelection = 0; + + // Setup onClick listener for this view. Rotates between each of the different selection + // states on each click. + // + // Notice that we call sendAccessibilityEvent here. Some AccessibilityEvents are generated + // by the system. However, custom views will typically need to send events manually as the + // user interacts with the view. The type of event sent will vary, depending on the nature + // of the view and how the user interacts with it. + // + // In this case, we are sending TYPE_VIEW_SELECTED rather than TYPE_VIEW_CLICKED, because + // clicking on this view selects a new value. + // + // We will give our AccessibilityEvent further information about the state of the view in + // onPopulateAccessibilityEvent(), which will be called automatically by the system + // for each AccessibilityEvent. + setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + // Rotate selection to the next valid choice. + mActiveSelection = (mActiveSelection + 1) % SELECTION_COUNT; + // Send an AccessibilityEvent, since the user has interacted with the view. + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); + // Redraw the entire view. (Inefficient, but this is sufficient for demonstration + // purposes.) + invalidate(); + } + }); + } + + /** + * This is where a View should populate outgoing accessibility events with its text content. + * While this method is free to modify event attributes other than text content, doing so + * should normally be performed in + * {@link #onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent)}. + *
+ *Note that the behavior of this method will typically vary, depending on the type of + * accessibility event is passed into it. The allowed values also very, and are documented + * in {@link android.view.accessibility.AccessibilityEvent}. + *
+ *Typically, this is where you'll describe the state of your custom view. You may also + * want to provide custom directions when the user has focused your view. + * + * @param event The accessibility event which to populate. + */ + // BEGIN_INCLUDE (on_populate_accessibility_event) + @Override + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + public void onPopulateAccessibilityEvent(AccessibilityEvent event) { + super.onPopulateAccessibilityEvent(event); + + // Detect what type of accessibility event is being passed in. + int eventType = event.getEventType(); + + // Common case: The user has interacted with our view in some way. State may or may not + // have been changed. Read out the current status of the view. + // + // We also set some other metadata which is not used by TalkBack, but could be used by + // other TTS engines. + if (eventType == AccessibilityEvent.TYPE_VIEW_SELECTED || + eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) { + event.getText().add("Mode selected: " + Integer.toString(mActiveSelection + 1) + "."); + event.setItemCount(SELECTION_COUNT); + event.setCurrentItemIndex(mActiveSelection); + } + + // When a user first focuses on our view, we'll also read out some simple instructions to + // make it clear that this is an interactive element. + if (eventType == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) { + event.getText().add("Tap to change."); + } + } + // END_INCLUDE (on_populate_accessibility_event) + + /** + * This is called during layout when the size of this view has changed. If + * you were just added to the view hierarchy, you're called with the old + * values of 0. + * + *
This is where we determine the drawing bounds for our custom view. + * + * @param w Current width of this view. + * @param h Current height of this view. + * @param oldw Old width of this view. + * @param oldh Old height of this view. + */ + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + // Account for padding + float xPadding = (float) (getPaddingLeft() + getPaddingRight()); + float yPadding = (float) (getPaddingTop() + getPaddingBottom()); + + // Compute available width/height + mWidth = w; + mHeight = h; + mWidthPadded = w - xPadding; + mHeightPadded = h - yPadding; + mRadius = (float) (Math.min(mWidth, mHeight) / 2 * 0.8); + } + + /** + * Render view content. + * + *
We render an outer grey circle to serve as our "dial", and then render a smaller black + * circle to server as our indicator. The position for the indicator is determined based + * on mActiveSelection. + * + * @param canvas the canvas on which the background will be drawn + */ + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + // Draw dial + canvas.drawCircle(mWidth / 2, mHeight / 2, (float) mRadius, mDialPaint); + + // Draw text labels + final float labelRadius = mRadius + 10; + for (int i = 0; i < SELECTION_COUNT; i++) { + float[] xyData = computeXYForPosition(i, labelRadius); + float x = xyData[0]; + float y = xyData[1]; + canvas.drawText(Integer.toString(i + 1), x, y, mTextPaint); + } + + // Draw indicator mark + final float markerRadius = mRadius - 35; + float[] xyData = computeXYForPosition(mActiveSelection, markerRadius); + float x = xyData[0]; + float y = xyData[1]; + canvas.drawCircle(x, y, 20, mTextPaint); + } + + /** + * Compute the X/Y-coordinates for a label or indicator, given the position number and radius + * where the label should be drawn. + * + * @param pos Zero based position index + * @param radius Radius where label/indicator is to be drawn. + * @return 2-element array. Element 0 is X-coordinate, element 1 is Y-coordinate. + */ + private float[] computeXYForPosition(final int pos, final float radius) { + float[] result = new float[2]; + Double startAngle = Math.PI * (9 / 8d); // Angles are in radiansq + Double angle = startAngle + (pos * (Math.PI / 4)); + result[0] = (float) (radius * Math.cos(angle)) + (mWidth / 2); + result[1] = (float) (radius * Math.sin(angle)) + (mHeight / 2); + return result; + } +} diff --git a/samples/browseable/BasicAccessibility/src/com.example.android.basicaccessibility/MainActivity.java b/samples/browseable/BasicAccessibility/src/com.example.android.basicaccessibility/MainActivity.java new file mode 100644 index 000000000..2777ad772 --- /dev/null +++ b/samples/browseable/BasicAccessibility/src/com.example.android.basicaccessibility/MainActivity.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.basicaccessibility; + +import android.app.Activity; +import android.os.Bundle; + +/** + * Basic activity class. + * + *
Responsible for rendering layout, and displaying some toasts to give buttons feedback. + * There's nothing terribly interesting in this class. All the interesting stuff is in + * res/layout/activity_main.xml and {@link DialView}. + */ +public class MainActivity extends Activity { + + /** + * Standard onCreate() implementation. Sets R.layout.activity_main as the layout. + */ + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.sample_main); + } +} diff --git a/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/Log.java b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/Log.java new file mode 100644 index 000000000..17503c568 --- /dev/null +++ b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/Log.java @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Helper class for a list (or tree) of LoggerNodes. + * + *
When this is set as the head of the list, + * an instance of it can function as a drop-in replacement for {@link android.util.Log}. + * Most of the methods in this class server only to map a method call in Log to its equivalent + * in LogNode.
+ */ +public class Log { + // Grabbing the native values from Android's native logging facilities, + // to make for easy migration and interop. + public static final int NONE = -1; + public static final int VERBOSE = android.util.Log.VERBOSE; + public static final int DEBUG = android.util.Log.DEBUG; + public static final int INFO = android.util.Log.INFO; + public static final int WARN = android.util.Log.WARN; + public static final int ERROR = android.util.Log.ERROR; + public static final int ASSERT = android.util.Log.ASSERT; + + // Stores the beginning of the LogNode topology. + private static LogNode mLogNode; + + /** + * Returns the next LogNode in the linked list. + */ + public static LogNode getLogNode() { + return mLogNode; + } + + /** + * Sets the LogNode data will be sent to. + */ + public static void setLogNode(LogNode node) { + mLogNode = node; + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void println(int priority, String tag, String msg, Throwable tr) { + if (mLogNode != null) { + mLogNode.println(priority, tag, msg, tr); + } + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + */ + public static void println(int priority, String tag, String msg) { + println(priority, tag, msg, null); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void v(String tag, String msg, Throwable tr) { + println(VERBOSE, tag, msg, tr); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void v(String tag, String msg) { + v(tag, msg, null); + } + + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void d(String tag, String msg, Throwable tr) { + println(DEBUG, tag, msg, tr); + } + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void d(String tag, String msg) { + d(tag, msg, null); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void i(String tag, String msg, Throwable tr) { + println(INFO, tag, msg, tr); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void i(String tag, String msg) { + i(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, String msg, Throwable tr) { + println(WARN, tag, msg, tr); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void w(String tag, String msg) { + w(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, Throwable tr) { + w(tag, null, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void e(String tag, String msg, Throwable tr) { + println(ERROR, tag, msg, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void e(String tag, String msg) { + e(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, String msg, Throwable tr) { + println(ASSERT, tag, msg, tr); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void wtf(String tag, String msg) { + wtf(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, Throwable tr) { + wtf(tag, null, tr); + } +} diff --git a/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogFragment.java new file mode 100644 index 000000000..b302acd4b --- /dev/null +++ b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogFragment.java @@ -0,0 +1,109 @@ +/* +* Copyright 2013 The Android Open Source Project +* +* 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. +*/ +/* + * Copyright 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ScrollView; + +/** + * Simple fraggment which contains a LogView and uses is to output log data it receives + * through the LogNode interface. + */ +public class LogFragment extends Fragment { + + private LogView mLogView; + private ScrollView mScrollView; + + public LogFragment() {} + + public View inflateViews() { + mScrollView = new ScrollView(getActivity()); + ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mScrollView.setLayoutParams(scrollParams); + + mLogView = new LogView(getActivity()); + ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams); + logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + mLogView.setLayoutParams(logParams); + mLogView.setClickable(true); + mLogView.setFocusable(true); + mLogView.setTypeface(Typeface.MONOSPACE); + + // Want to set padding as 16 dips, setPadding takes pixels. Hooray math! + int paddingDips = 16; + double scale = getResources().getDisplayMetrics().density; + int paddingPixels = (int) ((paddingDips * (scale)) + .5); + mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels); + mLogView.setCompoundDrawablePadding(paddingPixels); + + mLogView.setGravity(Gravity.BOTTOM); + mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium); + + mScrollView.addView(mLogView); + return mScrollView; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View result = inflateViews(); + + mLogView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + mScrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + }); + return result; + } + + public LogView getLogView() { + return mLogView; + } +} \ No newline at end of file diff --git a/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogNode.java b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogNode.java new file mode 100644 index 000000000..bc37cabc0 --- /dev/null +++ b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogNode.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Basic interface for a logging system that can output to one or more targets. + * Note that in addition to classes that will output these logs in some format, + * one can also implement this interface over a filter and insert that in the chain, + * such that no targets further down see certain data, or see manipulated forms of the data. + * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data + * it received to HTML and sent it along to the next node in the chain, without printing it + * anywhere. + */ +public interface LogNode { + + /** + * Instructs first LogNode in the list to print the log data provided. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public void println(int priority, String tag, String msg, Throwable tr); + +} diff --git a/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogView.java b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogView.java new file mode 100644 index 000000000..c01542b91 --- /dev/null +++ b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogView.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.app.Activity; +import android.content.Context; +import android.util.*; +import android.widget.TextView; + +/** Simple TextView which is used to output log data received through the LogNode interface. +*/ +public class LogView extends TextView implements LogNode { + + public LogView(Context context) { + super(context); + } + + public LogView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LogView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Formats the log data and prints it out to the LogView. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + + + String priorityStr = null; + + // For the purposes of this View, we want to print the priority as readable text. + switch(priority) { + case android.util.Log.VERBOSE: + priorityStr = "VERBOSE"; + break; + case android.util.Log.DEBUG: + priorityStr = "DEBUG"; + break; + case android.util.Log.INFO: + priorityStr = "INFO"; + break; + case android.util.Log.WARN: + priorityStr = "WARN"; + break; + case android.util.Log.ERROR: + priorityStr = "ERROR"; + break; + case android.util.Log.ASSERT: + priorityStr = "ASSERT"; + break; + default: + break; + } + + // Handily, the Log class has a facility for converting a stack trace into a usable string. + String exceptionStr = null; + if (tr != null) { + exceptionStr = android.util.Log.getStackTraceString(tr); + } + + // Take the priority, tag, message, and exception, and concatenate as necessary + // into one usable line of text. + final StringBuilder outputBuilder = new StringBuilder(); + + String delimiter = "\t"; + appendIfNotNull(outputBuilder, priorityStr, delimiter); + appendIfNotNull(outputBuilder, tag, delimiter); + appendIfNotNull(outputBuilder, msg, delimiter); + appendIfNotNull(outputBuilder, exceptionStr, delimiter); + + // In case this was originally called from an AsyncTask or some other off-UI thread, + // make sure the update occurs within the UI thread. + ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() { + @Override + public void run() { + // Display the text we just generated within the LogView. + appendToLog(outputBuilder.toString()); + } + }))); + + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } + + public LogNode getNext() { + return mNext; + } + + public void setNext(LogNode node) { + mNext = node; + } + + /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since + * the logger takes so many arguments that might be null, this method helps cut out some of the + * agonizing tedium of writing the same 3 lines over and over. + * @param source StringBuilder containing the text to append to. + * @param addStr The String to append + * @param delimiter The String to separate the source and appended strings. A tab or comma, + * for instance. + * @return The fully concatenated String as a StringBuilder + */ + private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) { + if (addStr != null) { + if (addStr.length() == 0) { + delimiter = ""; + } + + return source.append(addStr).append(delimiter); + } + return source; + } + + // The next LogNode in the chain. + LogNode mNext; + + /** Outputs the string as a new line of log data in the LogView. */ + public void appendToLog(String s) { + append("\n" + s); + } + + +} diff --git a/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogWrapper.java new file mode 100644 index 000000000..16a9e7ba2 --- /dev/null +++ b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/LogWrapper.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.util.Log; + +/** + * Helper class which wraps Android's native Log utility in the Logger interface. This way + * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously. + */ +public class LogWrapper implements LogNode { + + // For piping: The next node to receive Log data after this one has done its work. + private LogNode mNext; + + /** + * Returns the next LogNode in the linked list. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + + /** + * Prints data out to the console using Android's native log mechanism. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + // There actually are log methods that don't take a msg parameter. For now, + // if that's the case, just convert null to the empty string and move on. + String useMsg = msg; + if (useMsg == null) { + useMsg = ""; + } + + // If an exeption was provided, convert that exception to a usable string and attach + // it to the end of the msg method. + if (tr != null) { + msg += "\n" + Log.getStackTraceString(tr); + } + + // This is functionally identical to Log.x(tag, useMsg); + // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg) + Log.println(priority, tag, useMsg); + + // If this isn't the last node in the chain, move things along. + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } +} diff --git a/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/MessageOnlyLogFilter.java new file mode 100644 index 000000000..19967dcd4 --- /dev/null +++ b/samples/browseable/BasicAccessibility/src/com.example.android.common.logger/MessageOnlyLogFilter.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Simple {@link LogNode} filter, removes everything except the message. + * Useful for situations like on-screen log output where you don't want a lot of metadata displayed, + * just easy-to-read message updates as they're happening. + */ +public class MessageOnlyLogFilter implements LogNode { + + LogNode mNext; + + /** + * Takes the "next" LogNode as a parameter, to simplify chaining. + * + * @param next The next LogNode in the pipeline. + */ + public MessageOnlyLogFilter(LogNode next) { + mNext = next; + } + + public MessageOnlyLogFilter() { + } + + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + if (mNext != null) { + getNext().println(Log.NONE, null, msg, null); + } + } + + /** + * Returns the next LogNode in the chain. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + +} diff --git a/samples/browseable/BasicAndroidKeyStore/AndroidManifest.xml b/samples/browseable/BasicAndroidKeyStore/AndroidManifest.xml new file mode 100644 index 000000000..28d256c2d --- /dev/null +++ b/samples/browseable/BasicAndroidKeyStore/AndroidManifest.xml @@ -0,0 +1,41 @@ + + + + + ++ + Welcome to the Basic Android Key Store sample!\n\n + This sample demonstrates how to use the Android Key Store to safely create and store + encryption keys that only your application can access. You can also sign data + using those keys.\n\n + To create a new KeyPair, click \"Create\".\n\n + To sign some data using a KeyPair, click \"Sign\".\n\n + To verify the data using the signature provided, click \"Verify\".\n\n +
diff --git a/samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..b1efaf4b2 Binary files /dev/null and b/samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/tile.9.png new file mode 100644 index 000000000..135862883 Binary files /dev/null and b/samples/browseable/BasicAndroidKeyStore/res/drawable-hdpi/tile.9.png differ diff --git a/samples/browseable/BasicAndroidKeyStore/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..f5f9244f2 Binary files /dev/null and b/samples/browseable/BasicAndroidKeyStore/res/drawable-mdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicAndroidKeyStore/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..5d07b3f06 Binary files /dev/null and b/samples/browseable/BasicAndroidKeyStore/res/drawable-xhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicAndroidKeyStore/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicAndroidKeyStore/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..6ef21e1f4 Binary files /dev/null and b/samples/browseable/BasicAndroidKeyStore/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicAndroidKeyStore/res/layout/activity_main.xml b/samples/browseable/BasicAndroidKeyStore/res/layout/activity_main.xml new file mode 100644 index 000000000..bc5a57591 --- /dev/null +++ b/samples/browseable/BasicAndroidKeyStore/res/layout/activity_main.xml @@ -0,0 +1,38 @@ + +When this is set as the head of the list, + * an instance of it can function as a drop-in replacement for {@link android.util.Log}. + * Most of the methods in this class server only to map a method call in Log to its equivalent + * in LogNode.
+ */ +public class Log { + // Grabbing the native values from Android's native logging facilities, + // to make for easy migration and interop. + public static final int NONE = -1; + public static final int VERBOSE = android.util.Log.VERBOSE; + public static final int DEBUG = android.util.Log.DEBUG; + public static final int INFO = android.util.Log.INFO; + public static final int WARN = android.util.Log.WARN; + public static final int ERROR = android.util.Log.ERROR; + public static final int ASSERT = android.util.Log.ASSERT; + + // Stores the beginning of the LogNode topology. + private static LogNode mLogNode; + + /** + * Returns the next LogNode in the linked list. + */ + public static LogNode getLogNode() { + return mLogNode; + } + + /** + * Sets the LogNode data will be sent to. + */ + public static void setLogNode(LogNode node) { + mLogNode = node; + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void println(int priority, String tag, String msg, Throwable tr) { + if (mLogNode != null) { + mLogNode.println(priority, tag, msg, tr); + } + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + */ + public static void println(int priority, String tag, String msg) { + println(priority, tag, msg, null); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void v(String tag, String msg, Throwable tr) { + println(VERBOSE, tag, msg, tr); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void v(String tag, String msg) { + v(tag, msg, null); + } + + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void d(String tag, String msg, Throwable tr) { + println(DEBUG, tag, msg, tr); + } + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void d(String tag, String msg) { + d(tag, msg, null); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void i(String tag, String msg, Throwable tr) { + println(INFO, tag, msg, tr); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void i(String tag, String msg) { + i(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, String msg, Throwable tr) { + println(WARN, tag, msg, tr); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void w(String tag, String msg) { + w(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, Throwable tr) { + w(tag, null, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void e(String tag, String msg, Throwable tr) { + println(ERROR, tag, msg, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void e(String tag, String msg) { + e(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, String msg, Throwable tr) { + println(ASSERT, tag, msg, tr); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void wtf(String tag, String msg) { + wtf(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, Throwable tr) { + wtf(tag, null, tr); + } +} diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogFragment.java new file mode 100644 index 000000000..b302acd4b --- /dev/null +++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogFragment.java @@ -0,0 +1,109 @@ +/* +* Copyright 2013 The Android Open Source Project +* +* 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. +*/ +/* + * Copyright 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ScrollView; + +/** + * Simple fraggment which contains a LogView and uses is to output log data it receives + * through the LogNode interface. + */ +public class LogFragment extends Fragment { + + private LogView mLogView; + private ScrollView mScrollView; + + public LogFragment() {} + + public View inflateViews() { + mScrollView = new ScrollView(getActivity()); + ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mScrollView.setLayoutParams(scrollParams); + + mLogView = new LogView(getActivity()); + ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams); + logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + mLogView.setLayoutParams(logParams); + mLogView.setClickable(true); + mLogView.setFocusable(true); + mLogView.setTypeface(Typeface.MONOSPACE); + + // Want to set padding as 16 dips, setPadding takes pixels. Hooray math! + int paddingDips = 16; + double scale = getResources().getDisplayMetrics().density; + int paddingPixels = (int) ((paddingDips * (scale)) + .5); + mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels); + mLogView.setCompoundDrawablePadding(paddingPixels); + + mLogView.setGravity(Gravity.BOTTOM); + mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium); + + mScrollView.addView(mLogView); + return mScrollView; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View result = inflateViews(); + + mLogView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + mScrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + }); + return result; + } + + public LogView getLogView() { + return mLogView; + } +} \ No newline at end of file diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogNode.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogNode.java new file mode 100644 index 000000000..bc37cabc0 --- /dev/null +++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogNode.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Basic interface for a logging system that can output to one or more targets. + * Note that in addition to classes that will output these logs in some format, + * one can also implement this interface over a filter and insert that in the chain, + * such that no targets further down see certain data, or see manipulated forms of the data. + * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data + * it received to HTML and sent it along to the next node in the chain, without printing it + * anywhere. + */ +public interface LogNode { + + /** + * Instructs first LogNode in the list to print the log data provided. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public void println(int priority, String tag, String msg, Throwable tr); + +} diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogView.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogView.java new file mode 100644 index 000000000..c01542b91 --- /dev/null +++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogView.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.app.Activity; +import android.content.Context; +import android.util.*; +import android.widget.TextView; + +/** Simple TextView which is used to output log data received through the LogNode interface. +*/ +public class LogView extends TextView implements LogNode { + + public LogView(Context context) { + super(context); + } + + public LogView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LogView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Formats the log data and prints it out to the LogView. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + + + String priorityStr = null; + + // For the purposes of this View, we want to print the priority as readable text. + switch(priority) { + case android.util.Log.VERBOSE: + priorityStr = "VERBOSE"; + break; + case android.util.Log.DEBUG: + priorityStr = "DEBUG"; + break; + case android.util.Log.INFO: + priorityStr = "INFO"; + break; + case android.util.Log.WARN: + priorityStr = "WARN"; + break; + case android.util.Log.ERROR: + priorityStr = "ERROR"; + break; + case android.util.Log.ASSERT: + priorityStr = "ASSERT"; + break; + default: + break; + } + + // Handily, the Log class has a facility for converting a stack trace into a usable string. + String exceptionStr = null; + if (tr != null) { + exceptionStr = android.util.Log.getStackTraceString(tr); + } + + // Take the priority, tag, message, and exception, and concatenate as necessary + // into one usable line of text. + final StringBuilder outputBuilder = new StringBuilder(); + + String delimiter = "\t"; + appendIfNotNull(outputBuilder, priorityStr, delimiter); + appendIfNotNull(outputBuilder, tag, delimiter); + appendIfNotNull(outputBuilder, msg, delimiter); + appendIfNotNull(outputBuilder, exceptionStr, delimiter); + + // In case this was originally called from an AsyncTask or some other off-UI thread, + // make sure the update occurs within the UI thread. + ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() { + @Override + public void run() { + // Display the text we just generated within the LogView. + appendToLog(outputBuilder.toString()); + } + }))); + + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } + + public LogNode getNext() { + return mNext; + } + + public void setNext(LogNode node) { + mNext = node; + } + + /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since + * the logger takes so many arguments that might be null, this method helps cut out some of the + * agonizing tedium of writing the same 3 lines over and over. + * @param source StringBuilder containing the text to append to. + * @param addStr The String to append + * @param delimiter The String to separate the source and appended strings. A tab or comma, + * for instance. + * @return The fully concatenated String as a StringBuilder + */ + private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) { + if (addStr != null) { + if (addStr.length() == 0) { + delimiter = ""; + } + + return source.append(addStr).append(delimiter); + } + return source; + } + + // The next LogNode in the chain. + LogNode mNext; + + /** Outputs the string as a new line of log data in the LogView. */ + public void appendToLog(String s) { + append("\n" + s); + } + + +} diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogWrapper.java new file mode 100644 index 000000000..16a9e7ba2 --- /dev/null +++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/LogWrapper.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.util.Log; + +/** + * Helper class which wraps Android's native Log utility in the Logger interface. This way + * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously. + */ +public class LogWrapper implements LogNode { + + // For piping: The next node to receive Log data after this one has done its work. + private LogNode mNext; + + /** + * Returns the next LogNode in the linked list. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + + /** + * Prints data out to the console using Android's native log mechanism. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + // There actually are log methods that don't take a msg parameter. For now, + // if that's the case, just convert null to the empty string and move on. + String useMsg = msg; + if (useMsg == null) { + useMsg = ""; + } + + // If an exeption was provided, convert that exception to a usable string and attach + // it to the end of the msg method. + if (tr != null) { + msg += "\n" + Log.getStackTraceString(tr); + } + + // This is functionally identical to Log.x(tag, useMsg); + // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg) + Log.println(priority, tag, useMsg); + + // If this isn't the last node in the chain, move things along. + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } +} diff --git a/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/MessageOnlyLogFilter.java new file mode 100644 index 000000000..19967dcd4 --- /dev/null +++ b/samples/browseable/BasicAndroidKeyStore/src/com.example.android.common/logger/MessageOnlyLogFilter.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Simple {@link LogNode} filter, removes everything except the message. + * Useful for situations like on-screen log output where you don't want a lot of metadata displayed, + * just easy-to-read message updates as they're happening. + */ +public class MessageOnlyLogFilter implements LogNode { + + LogNode mNext; + + /** + * Takes the "next" LogNode as a parameter, to simplify chaining. + * + * @param next The next LogNode in the pipeline. + */ + public MessageOnlyLogFilter(LogNode next) { + mNext = next; + } + + public MessageOnlyLogFilter() { + } + + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + if (mNext != null) { + getNext().println(Log.NONE, null, msg, null); + } + } + + /** + * Returns the next LogNode in the chain. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + +} diff --git a/samples/browseable/BasicContactables/AndroidManifest.xml b/samples/browseable/BasicContactables/AndroidManifest.xml new file mode 100644 index 000000000..62b9812cc --- /dev/null +++ b/samples/browseable/BasicContactables/AndroidManifest.xml @@ -0,0 +1,52 @@ + + + ++ + This sample demonstrates how to use the Contactables table to search for contacts. + \n\nQuery strings sent to the Contactables table will match both contact names and phone numbers, + reducing the number of queries your application needs to use when searching the contacts database! + +
diff --git a/samples/browseable/BasicContactables/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicContactables/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..b1efaf4b2 Binary files /dev/null and b/samples/browseable/BasicContactables/res/drawable-hdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicContactables/res/drawable-hdpi/ic_search_api_holo_light.png b/samples/browseable/BasicContactables/res/drawable-hdpi/ic_search_api_holo_light.png new file mode 100644 index 000000000..72e207bc5 Binary files /dev/null and b/samples/browseable/BasicContactables/res/drawable-hdpi/ic_search_api_holo_light.png differ diff --git a/samples/browseable/BasicContactables/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicContactables/res/drawable-hdpi/tile.9.png new file mode 100644 index 000000000..135862883 Binary files /dev/null and b/samples/browseable/BasicContactables/res/drawable-hdpi/tile.9.png differ diff --git a/samples/browseable/BasicContactables/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicContactables/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..f5f9244f2 Binary files /dev/null and b/samples/browseable/BasicContactables/res/drawable-mdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicContactables/res/drawable-mdpi/ic_search_api_holo_light.png b/samples/browseable/BasicContactables/res/drawable-mdpi/ic_search_api_holo_light.png new file mode 100644 index 000000000..f2e26f883 Binary files /dev/null and b/samples/browseable/BasicContactables/res/drawable-mdpi/ic_search_api_holo_light.png differ diff --git a/samples/browseable/BasicContactables/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicContactables/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..5d07b3f06 Binary files /dev/null and b/samples/browseable/BasicContactables/res/drawable-xhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicContactables/res/drawable-xhdpi/ic_search_api_holo_light.png b/samples/browseable/BasicContactables/res/drawable-xhdpi/ic_search_api_holo_light.png new file mode 100644 index 000000000..a4cdf1c79 Binary files /dev/null and b/samples/browseable/BasicContactables/res/drawable-xhdpi/ic_search_api_holo_light.png differ diff --git a/samples/browseable/BasicContactables/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicContactables/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..6ef21e1f4 Binary files /dev/null and b/samples/browseable/BasicContactables/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicContactables/res/layout/activity_main.xml b/samples/browseable/BasicContactables/res/layout/activity_main.xml new file mode 100755 index 000000000..be1aa49d9 --- /dev/null +++ b/samples/browseable/BasicContactables/res/layout/activity_main.xml @@ -0,0 +1,36 @@ + + +When this is set as the head of the list, + * an instance of it can function as a drop-in replacement for {@link android.util.Log}. + * Most of the methods in this class server only to map a method call in Log to its equivalent + * in LogNode.
+ */ +public class Log { + // Grabbing the native values from Android's native logging facilities, + // to make for easy migration and interop. + public static final int NONE = -1; + public static final int VERBOSE = android.util.Log.VERBOSE; + public static final int DEBUG = android.util.Log.DEBUG; + public static final int INFO = android.util.Log.INFO; + public static final int WARN = android.util.Log.WARN; + public static final int ERROR = android.util.Log.ERROR; + public static final int ASSERT = android.util.Log.ASSERT; + + // Stores the beginning of the LogNode topology. + private static LogNode mLogNode; + + /** + * Returns the next LogNode in the linked list. + */ + public static LogNode getLogNode() { + return mLogNode; + } + + /** + * Sets the LogNode data will be sent to. + */ + public static void setLogNode(LogNode node) { + mLogNode = node; + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void println(int priority, String tag, String msg, Throwable tr) { + if (mLogNode != null) { + mLogNode.println(priority, tag, msg, tr); + } + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + */ + public static void println(int priority, String tag, String msg) { + println(priority, tag, msg, null); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void v(String tag, String msg, Throwable tr) { + println(VERBOSE, tag, msg, tr); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void v(String tag, String msg) { + v(tag, msg, null); + } + + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void d(String tag, String msg, Throwable tr) { + println(DEBUG, tag, msg, tr); + } + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void d(String tag, String msg) { + d(tag, msg, null); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void i(String tag, String msg, Throwable tr) { + println(INFO, tag, msg, tr); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void i(String tag, String msg) { + i(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, String msg, Throwable tr) { + println(WARN, tag, msg, tr); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void w(String tag, String msg) { + w(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, Throwable tr) { + w(tag, null, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void e(String tag, String msg, Throwable tr) { + println(ERROR, tag, msg, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void e(String tag, String msg) { + e(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, String msg, Throwable tr) { + println(ASSERT, tag, msg, tr); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void wtf(String tag, String msg) { + wtf(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, Throwable tr) { + wtf(tag, null, tr); + } +} diff --git a/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogFragment.java new file mode 100644 index 000000000..b302acd4b --- /dev/null +++ b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogFragment.java @@ -0,0 +1,109 @@ +/* +* Copyright 2013 The Android Open Source Project +* +* 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. +*/ +/* + * Copyright 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ScrollView; + +/** + * Simple fraggment which contains a LogView and uses is to output log data it receives + * through the LogNode interface. + */ +public class LogFragment extends Fragment { + + private LogView mLogView; + private ScrollView mScrollView; + + public LogFragment() {} + + public View inflateViews() { + mScrollView = new ScrollView(getActivity()); + ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mScrollView.setLayoutParams(scrollParams); + + mLogView = new LogView(getActivity()); + ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams); + logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + mLogView.setLayoutParams(logParams); + mLogView.setClickable(true); + mLogView.setFocusable(true); + mLogView.setTypeface(Typeface.MONOSPACE); + + // Want to set padding as 16 dips, setPadding takes pixels. Hooray math! + int paddingDips = 16; + double scale = getResources().getDisplayMetrics().density; + int paddingPixels = (int) ((paddingDips * (scale)) + .5); + mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels); + mLogView.setCompoundDrawablePadding(paddingPixels); + + mLogView.setGravity(Gravity.BOTTOM); + mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium); + + mScrollView.addView(mLogView); + return mScrollView; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View result = inflateViews(); + + mLogView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + mScrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + }); + return result; + } + + public LogView getLogView() { + return mLogView; + } +} \ No newline at end of file diff --git a/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogNode.java b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogNode.java new file mode 100644 index 000000000..bc37cabc0 --- /dev/null +++ b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogNode.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Basic interface for a logging system that can output to one or more targets. + * Note that in addition to classes that will output these logs in some format, + * one can also implement this interface over a filter and insert that in the chain, + * such that no targets further down see certain data, or see manipulated forms of the data. + * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data + * it received to HTML and sent it along to the next node in the chain, without printing it + * anywhere. + */ +public interface LogNode { + + /** + * Instructs first LogNode in the list to print the log data provided. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public void println(int priority, String tag, String msg, Throwable tr); + +} diff --git a/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogView.java b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogView.java new file mode 100644 index 000000000..c01542b91 --- /dev/null +++ b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogView.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.app.Activity; +import android.content.Context; +import android.util.*; +import android.widget.TextView; + +/** Simple TextView which is used to output log data received through the LogNode interface. +*/ +public class LogView extends TextView implements LogNode { + + public LogView(Context context) { + super(context); + } + + public LogView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LogView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Formats the log data and prints it out to the LogView. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + + + String priorityStr = null; + + // For the purposes of this View, we want to print the priority as readable text. + switch(priority) { + case android.util.Log.VERBOSE: + priorityStr = "VERBOSE"; + break; + case android.util.Log.DEBUG: + priorityStr = "DEBUG"; + break; + case android.util.Log.INFO: + priorityStr = "INFO"; + break; + case android.util.Log.WARN: + priorityStr = "WARN"; + break; + case android.util.Log.ERROR: + priorityStr = "ERROR"; + break; + case android.util.Log.ASSERT: + priorityStr = "ASSERT"; + break; + default: + break; + } + + // Handily, the Log class has a facility for converting a stack trace into a usable string. + String exceptionStr = null; + if (tr != null) { + exceptionStr = android.util.Log.getStackTraceString(tr); + } + + // Take the priority, tag, message, and exception, and concatenate as necessary + // into one usable line of text. + final StringBuilder outputBuilder = new StringBuilder(); + + String delimiter = "\t"; + appendIfNotNull(outputBuilder, priorityStr, delimiter); + appendIfNotNull(outputBuilder, tag, delimiter); + appendIfNotNull(outputBuilder, msg, delimiter); + appendIfNotNull(outputBuilder, exceptionStr, delimiter); + + // In case this was originally called from an AsyncTask or some other off-UI thread, + // make sure the update occurs within the UI thread. + ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() { + @Override + public void run() { + // Display the text we just generated within the LogView. + appendToLog(outputBuilder.toString()); + } + }))); + + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } + + public LogNode getNext() { + return mNext; + } + + public void setNext(LogNode node) { + mNext = node; + } + + /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since + * the logger takes so many arguments that might be null, this method helps cut out some of the + * agonizing tedium of writing the same 3 lines over and over. + * @param source StringBuilder containing the text to append to. + * @param addStr The String to append + * @param delimiter The String to separate the source and appended strings. A tab or comma, + * for instance. + * @return The fully concatenated String as a StringBuilder + */ + private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) { + if (addStr != null) { + if (addStr.length() == 0) { + delimiter = ""; + } + + return source.append(addStr).append(delimiter); + } + return source; + } + + // The next LogNode in the chain. + LogNode mNext; + + /** Outputs the string as a new line of log data in the LogView. */ + public void appendToLog(String s) { + append("\n" + s); + } + + +} diff --git a/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogWrapper.java new file mode 100644 index 000000000..16a9e7ba2 --- /dev/null +++ b/samples/browseable/BasicContactables/src/com.example.android.common.logger/LogWrapper.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.util.Log; + +/** + * Helper class which wraps Android's native Log utility in the Logger interface. This way + * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously. + */ +public class LogWrapper implements LogNode { + + // For piping: The next node to receive Log data after this one has done its work. + private LogNode mNext; + + /** + * Returns the next LogNode in the linked list. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + + /** + * Prints data out to the console using Android's native log mechanism. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + // There actually are log methods that don't take a msg parameter. For now, + // if that's the case, just convert null to the empty string and move on. + String useMsg = msg; + if (useMsg == null) { + useMsg = ""; + } + + // If an exeption was provided, convert that exception to a usable string and attach + // it to the end of the msg method. + if (tr != null) { + msg += "\n" + Log.getStackTraceString(tr); + } + + // This is functionally identical to Log.x(tag, useMsg); + // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg) + Log.println(priority, tag, useMsg); + + // If this isn't the last node in the chain, move things along. + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } +} diff --git a/samples/browseable/BasicContactables/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/BasicContactables/src/com.example.android.common.logger/MessageOnlyLogFilter.java new file mode 100644 index 000000000..19967dcd4 --- /dev/null +++ b/samples/browseable/BasicContactables/src/com.example.android.common.logger/MessageOnlyLogFilter.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Simple {@link LogNode} filter, removes everything except the message. + * Useful for situations like on-screen log output where you don't want a lot of metadata displayed, + * just easy-to-read message updates as they're happening. + */ +public class MessageOnlyLogFilter implements LogNode { + + LogNode mNext; + + /** + * Takes the "next" LogNode as a parameter, to simplify chaining. + * + * @param next The next LogNode in the pipeline. + */ + public MessageOnlyLogFilter(LogNode next) { + mNext = next; + } + + public MessageOnlyLogFilter() { + } + + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + if (mNext != null) { + getNext().println(Log.NONE, null, msg, null); + } + } + + /** + * Returns the next LogNode in the chain. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + +} diff --git a/samples/browseable/BasicGestureDetect/AndroidManifest.xml b/samples/browseable/BasicGestureDetect/AndroidManifest.xml new file mode 100644 index 000000000..1d7b3bdee --- /dev/null +++ b/samples/browseable/BasicGestureDetect/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + + + ++ + Welcome to Basic Gesture Detect! + In order to try this sample out, try dragging or tapping this text to see what happens! + +
diff --git a/samples/browseable/BasicGestureDetect/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicGestureDetect/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..b1efaf4b2 Binary files /dev/null and b/samples/browseable/BasicGestureDetect/res/drawable-hdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicGestureDetect/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicGestureDetect/res/drawable-hdpi/tile.9.png new file mode 100644 index 000000000..135862883 Binary files /dev/null and b/samples/browseable/BasicGestureDetect/res/drawable-hdpi/tile.9.png differ diff --git a/samples/browseable/BasicGestureDetect/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicGestureDetect/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..f5f9244f2 Binary files /dev/null and b/samples/browseable/BasicGestureDetect/res/drawable-mdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicGestureDetect/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicGestureDetect/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..5d07b3f06 Binary files /dev/null and b/samples/browseable/BasicGestureDetect/res/drawable-xhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicGestureDetect/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicGestureDetect/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..6ef21e1f4 Binary files /dev/null and b/samples/browseable/BasicGestureDetect/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicGestureDetect/res/layout/activity_main.xml b/samples/browseable/BasicGestureDetect/res/layout/activity_main.xml new file mode 100755 index 000000000..bc5a57591 --- /dev/null +++ b/samples/browseable/BasicGestureDetect/res/layout/activity_main.xml @@ -0,0 +1,38 @@ + +When this is set as the head of the list, + * an instance of it can function as a drop-in replacement for {@link android.util.Log}. + * Most of the methods in this class server only to map a method call in Log to its equivalent + * in LogNode.
+ */ +public class Log { + // Grabbing the native values from Android's native logging facilities, + // to make for easy migration and interop. + public static final int NONE = -1; + public static final int VERBOSE = android.util.Log.VERBOSE; + public static final int DEBUG = android.util.Log.DEBUG; + public static final int INFO = android.util.Log.INFO; + public static final int WARN = android.util.Log.WARN; + public static final int ERROR = android.util.Log.ERROR; + public static final int ASSERT = android.util.Log.ASSERT; + + // Stores the beginning of the LogNode topology. + private static LogNode mLogNode; + + /** + * Returns the next LogNode in the linked list. + */ + public static LogNode getLogNode() { + return mLogNode; + } + + /** + * Sets the LogNode data will be sent to. + */ + public static void setLogNode(LogNode node) { + mLogNode = node; + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void println(int priority, String tag, String msg, Throwable tr) { + if (mLogNode != null) { + mLogNode.println(priority, tag, msg, tr); + } + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + */ + public static void println(int priority, String tag, String msg) { + println(priority, tag, msg, null); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void v(String tag, String msg, Throwable tr) { + println(VERBOSE, tag, msg, tr); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void v(String tag, String msg) { + v(tag, msg, null); + } + + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void d(String tag, String msg, Throwable tr) { + println(DEBUG, tag, msg, tr); + } + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void d(String tag, String msg) { + d(tag, msg, null); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void i(String tag, String msg, Throwable tr) { + println(INFO, tag, msg, tr); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void i(String tag, String msg) { + i(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, String msg, Throwable tr) { + println(WARN, tag, msg, tr); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void w(String tag, String msg) { + w(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, Throwable tr) { + w(tag, null, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void e(String tag, String msg, Throwable tr) { + println(ERROR, tag, msg, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void e(String tag, String msg) { + e(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, String msg, Throwable tr) { + println(ASSERT, tag, msg, tr); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void wtf(String tag, String msg) { + wtf(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, Throwable tr) { + wtf(tag, null, tr); + } +} diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogFragment.java new file mode 100644 index 000000000..b302acd4b --- /dev/null +++ b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogFragment.java @@ -0,0 +1,109 @@ +/* +* Copyright 2013 The Android Open Source Project +* +* 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. +*/ +/* + * Copyright 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ScrollView; + +/** + * Simple fraggment which contains a LogView and uses is to output log data it receives + * through the LogNode interface. + */ +public class LogFragment extends Fragment { + + private LogView mLogView; + private ScrollView mScrollView; + + public LogFragment() {} + + public View inflateViews() { + mScrollView = new ScrollView(getActivity()); + ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mScrollView.setLayoutParams(scrollParams); + + mLogView = new LogView(getActivity()); + ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams); + logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + mLogView.setLayoutParams(logParams); + mLogView.setClickable(true); + mLogView.setFocusable(true); + mLogView.setTypeface(Typeface.MONOSPACE); + + // Want to set padding as 16 dips, setPadding takes pixels. Hooray math! + int paddingDips = 16; + double scale = getResources().getDisplayMetrics().density; + int paddingPixels = (int) ((paddingDips * (scale)) + .5); + mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels); + mLogView.setCompoundDrawablePadding(paddingPixels); + + mLogView.setGravity(Gravity.BOTTOM); + mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium); + + mScrollView.addView(mLogView); + return mScrollView; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View result = inflateViews(); + + mLogView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + mScrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + }); + return result; + } + + public LogView getLogView() { + return mLogView; + } +} \ No newline at end of file diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogNode.java b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogNode.java new file mode 100644 index 000000000..bc37cabc0 --- /dev/null +++ b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogNode.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Basic interface for a logging system that can output to one or more targets. + * Note that in addition to classes that will output these logs in some format, + * one can also implement this interface over a filter and insert that in the chain, + * such that no targets further down see certain data, or see manipulated forms of the data. + * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data + * it received to HTML and sent it along to the next node in the chain, without printing it + * anywhere. + */ +public interface LogNode { + + /** + * Instructs first LogNode in the list to print the log data provided. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public void println(int priority, String tag, String msg, Throwable tr); + +} diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogView.java b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogView.java new file mode 100644 index 000000000..c01542b91 --- /dev/null +++ b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogView.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.app.Activity; +import android.content.Context; +import android.util.*; +import android.widget.TextView; + +/** Simple TextView which is used to output log data received through the LogNode interface. +*/ +public class LogView extends TextView implements LogNode { + + public LogView(Context context) { + super(context); + } + + public LogView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LogView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Formats the log data and prints it out to the LogView. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + + + String priorityStr = null; + + // For the purposes of this View, we want to print the priority as readable text. + switch(priority) { + case android.util.Log.VERBOSE: + priorityStr = "VERBOSE"; + break; + case android.util.Log.DEBUG: + priorityStr = "DEBUG"; + break; + case android.util.Log.INFO: + priorityStr = "INFO"; + break; + case android.util.Log.WARN: + priorityStr = "WARN"; + break; + case android.util.Log.ERROR: + priorityStr = "ERROR"; + break; + case android.util.Log.ASSERT: + priorityStr = "ASSERT"; + break; + default: + break; + } + + // Handily, the Log class has a facility for converting a stack trace into a usable string. + String exceptionStr = null; + if (tr != null) { + exceptionStr = android.util.Log.getStackTraceString(tr); + } + + // Take the priority, tag, message, and exception, and concatenate as necessary + // into one usable line of text. + final StringBuilder outputBuilder = new StringBuilder(); + + String delimiter = "\t"; + appendIfNotNull(outputBuilder, priorityStr, delimiter); + appendIfNotNull(outputBuilder, tag, delimiter); + appendIfNotNull(outputBuilder, msg, delimiter); + appendIfNotNull(outputBuilder, exceptionStr, delimiter); + + // In case this was originally called from an AsyncTask or some other off-UI thread, + // make sure the update occurs within the UI thread. + ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() { + @Override + public void run() { + // Display the text we just generated within the LogView. + appendToLog(outputBuilder.toString()); + } + }))); + + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } + + public LogNode getNext() { + return mNext; + } + + public void setNext(LogNode node) { + mNext = node; + } + + /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since + * the logger takes so many arguments that might be null, this method helps cut out some of the + * agonizing tedium of writing the same 3 lines over and over. + * @param source StringBuilder containing the text to append to. + * @param addStr The String to append + * @param delimiter The String to separate the source and appended strings. A tab or comma, + * for instance. + * @return The fully concatenated String as a StringBuilder + */ + private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) { + if (addStr != null) { + if (addStr.length() == 0) { + delimiter = ""; + } + + return source.append(addStr).append(delimiter); + } + return source; + } + + // The next LogNode in the chain. + LogNode mNext; + + /** Outputs the string as a new line of log data in the LogView. */ + public void appendToLog(String s) { + append("\n" + s); + } + + +} diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogWrapper.java new file mode 100644 index 000000000..16a9e7ba2 --- /dev/null +++ b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/LogWrapper.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.util.Log; + +/** + * Helper class which wraps Android's native Log utility in the Logger interface. This way + * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously. + */ +public class LogWrapper implements LogNode { + + // For piping: The next node to receive Log data after this one has done its work. + private LogNode mNext; + + /** + * Returns the next LogNode in the linked list. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + + /** + * Prints data out to the console using Android's native log mechanism. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + // There actually are log methods that don't take a msg parameter. For now, + // if that's the case, just convert null to the empty string and move on. + String useMsg = msg; + if (useMsg == null) { + useMsg = ""; + } + + // If an exeption was provided, convert that exception to a usable string and attach + // it to the end of the msg method. + if (tr != null) { + msg += "\n" + Log.getStackTraceString(tr); + } + + // This is functionally identical to Log.x(tag, useMsg); + // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg) + Log.println(priority, tag, useMsg); + + // If this isn't the last node in the chain, move things along. + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } +} diff --git a/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/MessageOnlyLogFilter.java new file mode 100644 index 000000000..19967dcd4 --- /dev/null +++ b/samples/browseable/BasicGestureDetect/src/com.example.android.common/logger/MessageOnlyLogFilter.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Simple {@link LogNode} filter, removes everything except the message. + * Useful for situations like on-screen log output where you don't want a lot of metadata displayed, + * just easy-to-read message updates as they're happening. + */ +public class MessageOnlyLogFilter implements LogNode { + + LogNode mNext; + + /** + * Takes the "next" LogNode as a parameter, to simplify chaining. + * + * @param next The next LogNode in the pipeline. + */ + public MessageOnlyLogFilter(LogNode next) { + mNext = next; + } + + public MessageOnlyLogFilter() { + } + + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + if (mNext != null) { + getNext().println(Log.NONE, null, msg, null); + } + } + + /** + * Returns the next LogNode in the chain. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + +} diff --git a/samples/browseable/BasicImmersiveMode/AndroidManifest.xml b/samples/browseable/BasicImmersiveMode/AndroidManifest.xml new file mode 100644 index 000000000..00b4e3c64 --- /dev/null +++ b/samples/browseable/BasicImmersiveMode/AndroidManifest.xml @@ -0,0 +1,38 @@ + + ++ + \"Immersive Mode\" is a new UI mode which improves \"hide full screen\" and + \"hide nav bar\" modes, by letting users swipe the bars in and out. This sample + demonstrates how to enable and disable immersive mode programmatically. + +
diff --git a/samples/browseable/BasicImmersiveMode/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicImmersiveMode/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..b1efaf4b2 Binary files /dev/null and b/samples/browseable/BasicImmersiveMode/res/drawable-hdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicImmersiveMode/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicImmersiveMode/res/drawable-hdpi/tile.9.png new file mode 100644 index 000000000..135862883 Binary files /dev/null and b/samples/browseable/BasicImmersiveMode/res/drawable-hdpi/tile.9.png differ diff --git a/samples/browseable/BasicImmersiveMode/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicImmersiveMode/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..f5f9244f2 Binary files /dev/null and b/samples/browseable/BasicImmersiveMode/res/drawable-mdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicImmersiveMode/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicImmersiveMode/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..5d07b3f06 Binary files /dev/null and b/samples/browseable/BasicImmersiveMode/res/drawable-xhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicImmersiveMode/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicImmersiveMode/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..6ef21e1f4 Binary files /dev/null and b/samples/browseable/BasicImmersiveMode/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicImmersiveMode/res/layout/activity_main.xml b/samples/browseable/BasicImmersiveMode/res/layout/activity_main.xml new file mode 100755 index 000000000..bc5a57591 --- /dev/null +++ b/samples/browseable/BasicImmersiveMode/res/layout/activity_main.xml @@ -0,0 +1,38 @@ + +When this is set as the head of the list, + * an instance of it can function as a drop-in replacement for {@link android.util.Log}. + * Most of the methods in this class server only to map a method call in Log to its equivalent + * in LogNode.
+ */ +public class Log { + // Grabbing the native values from Android's native logging facilities, + // to make for easy migration and interop. + public static final int NONE = -1; + public static final int VERBOSE = android.util.Log.VERBOSE; + public static final int DEBUG = android.util.Log.DEBUG; + public static final int INFO = android.util.Log.INFO; + public static final int WARN = android.util.Log.WARN; + public static final int ERROR = android.util.Log.ERROR; + public static final int ASSERT = android.util.Log.ASSERT; + + // Stores the beginning of the LogNode topology. + private static LogNode mLogNode; + + /** + * Returns the next LogNode in the linked list. + */ + public static LogNode getLogNode() { + return mLogNode; + } + + /** + * Sets the LogNode data will be sent to. + */ + public static void setLogNode(LogNode node) { + mLogNode = node; + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void println(int priority, String tag, String msg, Throwable tr) { + if (mLogNode != null) { + mLogNode.println(priority, tag, msg, tr); + } + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + */ + public static void println(int priority, String tag, String msg) { + println(priority, tag, msg, null); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void v(String tag, String msg, Throwable tr) { + println(VERBOSE, tag, msg, tr); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void v(String tag, String msg) { + v(tag, msg, null); + } + + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void d(String tag, String msg, Throwable tr) { + println(DEBUG, tag, msg, tr); + } + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void d(String tag, String msg) { + d(tag, msg, null); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void i(String tag, String msg, Throwable tr) { + println(INFO, tag, msg, tr); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void i(String tag, String msg) { + i(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, String msg, Throwable tr) { + println(WARN, tag, msg, tr); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void w(String tag, String msg) { + w(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, Throwable tr) { + w(tag, null, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void e(String tag, String msg, Throwable tr) { + println(ERROR, tag, msg, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void e(String tag, String msg) { + e(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, String msg, Throwable tr) { + println(ASSERT, tag, msg, tr); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void wtf(String tag, String msg) { + wtf(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, Throwable tr) { + wtf(tag, null, tr); + } +} diff --git a/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogFragment.java b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogFragment.java new file mode 100644 index 000000000..b302acd4b --- /dev/null +++ b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogFragment.java @@ -0,0 +1,109 @@ +/* +* Copyright 2013 The Android Open Source Project +* +* 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. +*/ +/* + * Copyright 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ScrollView; + +/** + * Simple fraggment which contains a LogView and uses is to output log data it receives + * through the LogNode interface. + */ +public class LogFragment extends Fragment { + + private LogView mLogView; + private ScrollView mScrollView; + + public LogFragment() {} + + public View inflateViews() { + mScrollView = new ScrollView(getActivity()); + ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mScrollView.setLayoutParams(scrollParams); + + mLogView = new LogView(getActivity()); + ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams); + logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + mLogView.setLayoutParams(logParams); + mLogView.setClickable(true); + mLogView.setFocusable(true); + mLogView.setTypeface(Typeface.MONOSPACE); + + // Want to set padding as 16 dips, setPadding takes pixels. Hooray math! + int paddingDips = 16; + double scale = getResources().getDisplayMetrics().density; + int paddingPixels = (int) ((paddingDips * (scale)) + .5); + mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels); + mLogView.setCompoundDrawablePadding(paddingPixels); + + mLogView.setGravity(Gravity.BOTTOM); + mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium); + + mScrollView.addView(mLogView); + return mScrollView; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View result = inflateViews(); + + mLogView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + mScrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + }); + return result; + } + + public LogView getLogView() { + return mLogView; + } +} \ No newline at end of file diff --git a/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogNode.java b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogNode.java new file mode 100644 index 000000000..bc37cabc0 --- /dev/null +++ b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogNode.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Basic interface for a logging system that can output to one or more targets. + * Note that in addition to classes that will output these logs in some format, + * one can also implement this interface over a filter and insert that in the chain, + * such that no targets further down see certain data, or see manipulated forms of the data. + * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data + * it received to HTML and sent it along to the next node in the chain, without printing it + * anywhere. + */ +public interface LogNode { + + /** + * Instructs first LogNode in the list to print the log data provided. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public void println(int priority, String tag, String msg, Throwable tr); + +} diff --git a/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogView.java b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogView.java new file mode 100644 index 000000000..c01542b91 --- /dev/null +++ b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogView.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.app.Activity; +import android.content.Context; +import android.util.*; +import android.widget.TextView; + +/** Simple TextView which is used to output log data received through the LogNode interface. +*/ +public class LogView extends TextView implements LogNode { + + public LogView(Context context) { + super(context); + } + + public LogView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LogView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Formats the log data and prints it out to the LogView. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + + + String priorityStr = null; + + // For the purposes of this View, we want to print the priority as readable text. + switch(priority) { + case android.util.Log.VERBOSE: + priorityStr = "VERBOSE"; + break; + case android.util.Log.DEBUG: + priorityStr = "DEBUG"; + break; + case android.util.Log.INFO: + priorityStr = "INFO"; + break; + case android.util.Log.WARN: + priorityStr = "WARN"; + break; + case android.util.Log.ERROR: + priorityStr = "ERROR"; + break; + case android.util.Log.ASSERT: + priorityStr = "ASSERT"; + break; + default: + break; + } + + // Handily, the Log class has a facility for converting a stack trace into a usable string. + String exceptionStr = null; + if (tr != null) { + exceptionStr = android.util.Log.getStackTraceString(tr); + } + + // Take the priority, tag, message, and exception, and concatenate as necessary + // into one usable line of text. + final StringBuilder outputBuilder = new StringBuilder(); + + String delimiter = "\t"; + appendIfNotNull(outputBuilder, priorityStr, delimiter); + appendIfNotNull(outputBuilder, tag, delimiter); + appendIfNotNull(outputBuilder, msg, delimiter); + appendIfNotNull(outputBuilder, exceptionStr, delimiter); + + // In case this was originally called from an AsyncTask or some other off-UI thread, + // make sure the update occurs within the UI thread. + ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() { + @Override + public void run() { + // Display the text we just generated within the LogView. + appendToLog(outputBuilder.toString()); + } + }))); + + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } + + public LogNode getNext() { + return mNext; + } + + public void setNext(LogNode node) { + mNext = node; + } + + /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since + * the logger takes so many arguments that might be null, this method helps cut out some of the + * agonizing tedium of writing the same 3 lines over and over. + * @param source StringBuilder containing the text to append to. + * @param addStr The String to append + * @param delimiter The String to separate the source and appended strings. A tab or comma, + * for instance. + * @return The fully concatenated String as a StringBuilder + */ + private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) { + if (addStr != null) { + if (addStr.length() == 0) { + delimiter = ""; + } + + return source.append(addStr).append(delimiter); + } + return source; + } + + // The next LogNode in the chain. + LogNode mNext; + + /** Outputs the string as a new line of log data in the LogView. */ + public void appendToLog(String s) { + append("\n" + s); + } + + +} diff --git a/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogWrapper.java b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogWrapper.java new file mode 100644 index 000000000..16a9e7ba2 --- /dev/null +++ b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/LogWrapper.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.util.Log; + +/** + * Helper class which wraps Android's native Log utility in the Logger interface. This way + * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously. + */ +public class LogWrapper implements LogNode { + + // For piping: The next node to receive Log data after this one has done its work. + private LogNode mNext; + + /** + * Returns the next LogNode in the linked list. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + + /** + * Prints data out to the console using Android's native log mechanism. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + // There actually are log methods that don't take a msg parameter. For now, + // if that's the case, just convert null to the empty string and move on. + String useMsg = msg; + if (useMsg == null) { + useMsg = ""; + } + + // If an exeption was provided, convert that exception to a usable string and attach + // it to the end of the msg method. + if (tr != null) { + msg += "\n" + Log.getStackTraceString(tr); + } + + // This is functionally identical to Log.x(tag, useMsg); + // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg) + Log.println(priority, tag, useMsg); + + // If this isn't the last node in the chain, move things along. + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } +} diff --git a/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.java b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.java new file mode 100644 index 000000000..19967dcd4 --- /dev/null +++ b/samples/browseable/BasicImmersiveMode/src/com.example.android.common/logger/MessageOnlyLogFilter.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Simple {@link LogNode} filter, removes everything except the message. + * Useful for situations like on-screen log output where you don't want a lot of metadata displayed, + * just easy-to-read message updates as they're happening. + */ +public class MessageOnlyLogFilter implements LogNode { + + LogNode mNext; + + /** + * Takes the "next" LogNode as a parameter, to simplify chaining. + * + * @param next The next LogNode in the pipeline. + */ + public MessageOnlyLogFilter(LogNode next) { + mNext = next; + } + + public MessageOnlyLogFilter() { + } + + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + if (mNext != null) { + getNext().println(Log.NONE, null, msg, null); + } + } + + /** + * Returns the next LogNode in the chain. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + +} diff --git a/samples/browseable/BasicMediaDecoder/AndroidManifest.xml b/samples/browseable/BasicMediaDecoder/AndroidManifest.xml new file mode 100644 index 000000000..d19149110 --- /dev/null +++ b/samples/browseable/BasicMediaDecoder/AndroidManifest.xml @@ -0,0 +1,37 @@ + + + ++ + This activity uses a TextureView to render the frames of a video decoded using the + MediaCodec API. + +
diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_action_play.png b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_action_play.png new file mode 100755 index 000000000..dbfd337a5 Binary files /dev/null and b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_action_play.png differ diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_action_play_disabled.png b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_action_play_disabled.png new file mode 100755 index 000000000..e4310efc6 Binary files /dev/null and b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_action_play_disabled.png differ diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..9bc536b31 Binary files /dev/null and b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/tile.9.png new file mode 100644 index 000000000..135862883 Binary files /dev/null and b/samples/browseable/BasicMediaDecoder/res/drawable-hdpi/tile.9.png differ diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_action_play.png b/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_action_play.png new file mode 100755 index 000000000..a2f198aef Binary files /dev/null and b/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_action_play.png differ diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_action_play_disabled.png b/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_action_play_disabled.png new file mode 100755 index 000000000..d69107baa Binary files /dev/null and b/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_action_play_disabled.png differ diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..d656b2157 Binary files /dev/null and b/samples/browseable/BasicMediaDecoder/res/drawable-mdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play.png b/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play.png new file mode 100755 index 000000000..9e63c90be Binary files /dev/null and b/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play.png differ diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play_disabled.png b/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play_disabled.png new file mode 100755 index 000000000..2ff8c3992 Binary files /dev/null and b/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_action_play_disabled.png differ diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..bbb9b1642 Binary files /dev/null and b/samples/browseable/BasicMediaDecoder/res/drawable-xhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicMediaDecoder/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicMediaDecoder/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..4a5c33f10 Binary files /dev/null and b/samples/browseable/BasicMediaDecoder/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicMediaDecoder/res/drawable/selector_play.xml b/samples/browseable/BasicMediaDecoder/res/drawable/selector_play.xml new file mode 100644 index 000000000..23071359e --- /dev/null +++ b/samples/browseable/BasicMediaDecoder/res/drawable/selector_play.xml @@ -0,0 +1,9 @@ + + ++ + This sample demonstrates the use of the MediaRouter API to display + content on a secondary display.\n\nUse the "Media Route Action Item" in the ActionBar + to select an output device. If your device supports Miracast wireless displays, + you may need to enable "Wireless Display" functionality in the system settings. + Secondary screen simulation can also be enabled from the "Developer Options".\n\n +Once connected, use the "Change Color" button to change the background color of the secondary screen. + +
diff --git a/samples/browseable/BasicMediaRouter/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicMediaRouter/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..b1efaf4b2 Binary files /dev/null and b/samples/browseable/BasicMediaRouter/res/drawable-hdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicMediaRouter/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicMediaRouter/res/drawable-hdpi/tile.9.png new file mode 100644 index 000000000..135862883 Binary files /dev/null and b/samples/browseable/BasicMediaRouter/res/drawable-hdpi/tile.9.png differ diff --git a/samples/browseable/BasicMediaRouter/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicMediaRouter/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..f5f9244f2 Binary files /dev/null and b/samples/browseable/BasicMediaRouter/res/drawable-mdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicMediaRouter/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicMediaRouter/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..5d07b3f06 Binary files /dev/null and b/samples/browseable/BasicMediaRouter/res/drawable-xhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicMediaRouter/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicMediaRouter/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..6ef21e1f4 Binary files /dev/null and b/samples/browseable/BasicMediaRouter/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicMediaRouter/res/layout/activity_main.xml b/samples/browseable/BasicMediaRouter/res/layout/activity_main.xml new file mode 100755 index 000000000..be1aa49d9 --- /dev/null +++ b/samples/browseable/BasicMediaRouter/res/layout/activity_main.xml @@ -0,0 +1,36 @@ + + ++ * This sample demonstrates the use of the MediaRouter API to show content on a + * secondary display using a {@link android.app.Presentation}. + *
+ *+ * The activity uses the {@link android.media.MediaRouter} API to automatically detect when a + * presentation display is available and to allow the user to control the media + * routes using a menu item provided by the {@link android.app.MediaRouteActionProvider}. + * When a presentation display is available a {@link android.app.Presentation} (implemented + * as a {@link SamplePresentation}) is shown on the preferred display. A button + * toggles the background color of the secondary screen to show the interaction + * between the primary and secondary screens. + *
+ *+ * This sample requires an HDMI or Wifi display. Alternatively, the + * "Simulate secondary displays" feature in Development Settings can be enabled + * to simulate secondary displays. + *
+ * + * @see android.app.Presentation + * @see android.media.MediaRouter + */ +public class MainActivity extends Activity { + + private MediaRouter mMediaRouter; + + // Active Presentation, set to null if no secondary screen is enabled + private SamplePresentation mPresentation; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.sample_main); + mTextStatus = (TextView) findViewById(R.id.textStatus); + + // get the list of background colors + mColors = getResources().getIntArray(R.array.androidcolors); + + // Enable clicks on the 'change color' button + mButton = (Button) findViewById(R.id.button1); + mButton.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + showNextColor(); + } + }); + + // BEGIN_INCLUDE(getMediaRouter) + // Get the MediaRouter service + mMediaRouter = (MediaRouter) getSystemService(Context.MEDIA_ROUTER_SERVICE); + // END_INCLUDE(getMediaRouter) + } + + /** + * Implementing a {@link android.media.MediaRouter.Callback} to update the displayed + * {@link android.app.Presentation} when a route is selected, unselected or the + * presentation display has changed. The provided stub implementation + * {@link android.media.MediaRouter.SimpleCallback} is extended and only + * {@link android.media.MediaRouter.SimpleCallback#onRouteSelected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo)} + * , + * {@link android.media.MediaRouter.SimpleCallback#onRouteUnselected(android.media.MediaRouter, int, android.media.MediaRouter.RouteInfo)} + * and + * {@link android.media.MediaRouter.SimpleCallback#onRoutePresentationDisplayChanged(android.media.MediaRouter, android.media.MediaRouter.RouteInfo)} + * are overridden to update the displayed {@link android.app.Presentation} in + * {@link #updatePresentation()}. These callbacks enable or disable the + * second screen presentation based on the routing provided by the + * {@link android.media.MediaRouter} for {@link android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO} + * streams. @ + */ + private final MediaRouter.SimpleCallback mMediaRouterCallback = + new MediaRouter.SimpleCallback() { + + // BEGIN_INCLUDE(SimpleCallback) + /** + * A new route has been selected as active. Disable the current + * route and enable the new one. + */ + @Override + public void onRouteSelected(MediaRouter router, int type, RouteInfo info) { + updatePresentation(); + } + + /** + * The route has been unselected. + */ + @Override + public void onRouteUnselected(MediaRouter router, int type, RouteInfo info) { + updatePresentation(); + + } + + /** + * The route's presentation display has changed. This callback + * is called when the presentation has been activated, removed + * or its properties have changed. + */ + @Override + public void onRoutePresentationDisplayChanged(MediaRouter router, RouteInfo info) { + updatePresentation(); + } + // END_INCLUDE(SimpleCallback) + }; + + /** + * Updates the displayed presentation to enable a secondary screen if it has + * been selected in the {@link android.media.MediaRouter} for the + * {@link android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO} type. If no screen has been + * selected by the {@link android.media.MediaRouter}, the current screen is disabled. + * Otherwise a new {@link SamplePresentation} is initialized and shown on + * the secondary screen. + */ + private void updatePresentation() { + + // BEGIN_INCLUDE(updatePresentationInit) + // Get the selected route for live video + RouteInfo selectedRoute = mMediaRouter.getSelectedRoute( + MediaRouter.ROUTE_TYPE_LIVE_VIDEO); + + // Get its Display if a valid route has been selected + Display selectedDisplay = null; + if (selectedRoute != null) { + selectedDisplay = selectedRoute.getPresentationDisplay(); + } + // END_INCLUDE(updatePresentationInit) + + // BEGIN_INCLUDE(updatePresentationDismiss) + /* + * Dismiss the current presentation if the display has changed or no new + * route has been selected + */ + if (mPresentation != null && mPresentation.getDisplay() != selectedDisplay) { + mPresentation.dismiss(); + mPresentation = null; + mButton.setEnabled(false); + mTextStatus.setText(R.string.secondary_notconnected); + } + // END_INCLUDE(updatePresentationDismiss) + + // BEGIN_INCLUDE(updatePresentationNew) + /* + * Show a new presentation if the previous one has been dismissed and a + * route has been selected. + */ + if (mPresentation == null && selectedDisplay != null) { + + // Initialise a new Presentation for the Display + mPresentation = new SamplePresentation(this, selectedDisplay); + mPresentation.setOnDismissListener(mOnDismissListener); + + // Try to show the presentation, this might fail if the display has + // gone away in the mean time + try { + mPresentation.show(); + mTextStatus.setText(getResources().getString(R.string.secondary_connected, + selectedRoute.getName(MainActivity.this))); + mButton.setEnabled(true); + showNextColor(); + } catch (WindowManager.InvalidDisplayException ex) { + // Couldn't show presentation - display was already removed + mPresentation = null; + } + } + // END_INCLUDE(updatePresentationNew) + + } + + @Override + protected void onResume() { + super.onResume(); + + // BEGIN_INCLUDE(addCallback) + // Register a callback for all events related to live video devices + mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_LIVE_VIDEO, mMediaRouterCallback); + // END_INCLUDE(addCallback) + + // Show the 'Not connected' status message + mButton.setEnabled(false); + mTextStatus.setText(R.string.secondary_notconnected); + + // Update the displays based on the currently active routes + updatePresentation(); + } + + @Override + protected void onPause() { + super.onPause(); + + // BEGIN_INCLUDE(onPause) + // Stop listening for changes to media routes. + mMediaRouter.removeCallback(mMediaRouterCallback); + // END_INCLUDE(onPause) + } + + @Override + protected void onStop() { + super.onStop(); + + // BEGIN_INCLUDE(onStop) + // Dismiss the presentation when the activity is not visible. + if (mPresentation != null) { + mPresentation.dismiss(); + mPresentation = null; + } + // BEGIN_INCLUDE(onStop) + } + + /** + * Inflates the ActionBar or options menu. The menu file defines an item for + * the {@link android.app.MediaRouteActionProvider}, which is registered here for all + * live video devices using {@link android.media.MediaRouter#ROUTE_TYPE_LIVE_VIDEO}. + */ + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + + getMenuInflater().inflate(R.menu.main, menu); + + // BEGIN_INCLUDE(MediaRouteActionProvider) + // Configure the media router action provider + MenuItem mediaRouteMenuItem = menu.findItem(R.id.menu_media_route); + MediaRouteActionProvider mediaRouteActionProvider = + (MediaRouteActionProvider) mediaRouteMenuItem.getActionProvider(); + mediaRouteActionProvider.setRouteTypes(MediaRouter.ROUTE_TYPE_LIVE_VIDEO); + // BEGIN_INCLUDE(MediaRouteActionProvider) + + return true; + } + + /** + * Listens for dismissal of the {@link SamplePresentation} and removes its + * reference. + */ + private final DialogInterface.OnDismissListener mOnDismissListener = + new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + if (dialog == mPresentation) { + mPresentation = null; + } + } + }; + + // Views used to display status information on the primary screen + private TextView mTextStatus; + private Button mButton; + + // selected color index + private int mColor = 0; + + // background colors + public int[] mColors; + + /** + * Displays the next color on the secondary screen if it is activate. + */ + private void showNextColor() { + if (mPresentation != null) { + // a second screen is active and initialized, show the next color + mPresentation.setColor(mColors[mColor]); + mColor = (mColor + 1) % mColors.length; + } + } + +} diff --git a/samples/browseable/BasicMediaRouter/src/com.example.android.basicmediarouter/SamplePresentation.java b/samples/browseable/BasicMediaRouter/src/com.example.android.basicmediarouter/SamplePresentation.java new file mode 100644 index 000000000..ac1f40f29 --- /dev/null +++ b/samples/browseable/BasicMediaRouter/src/com.example.android.basicmediarouter/SamplePresentation.java @@ -0,0 +1,78 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * 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.example.android.basicmediarouter; + +import android.app.Presentation; +import android.content.Context; +import android.os.Bundle; +import android.view.Display; +import android.widget.LinearLayout; +import android.widget.TextView; + +/** + *+ * A {@link android.app.Presentation} used to demonstrate interaction between primary and + * secondary screens. + *
+ *+ * It displays the name of the display in which it has been embedded (see + * {@link android.app.Presentation#getDisplay()}) and exposes a facility to change its + * background color and display its text. + *
+ */ +public class SamplePresentation extends Presentation { + + private LinearLayout mLayout; + private TextView mText; + + public SamplePresentation(Context outerContext, Display display) { + super(outerContext, display); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Set the content view to the custom layout + setContentView(R.layout.display); + + // Get the Views + mLayout = (LinearLayout) findViewById(R.id.display_layout); + mText = (TextView) findViewById(R.id.display_text); + + /* + * Show the name of the display this presentation was embedded in. + */ + TextView smallText = (TextView) findViewById(R.id.display_smalltext); + final String name = getDisplay().getName(); + smallText.setText(getResources().getString(R.string.display_name, name)); + } + + /** + * Set the background color of the layout and display the color as a String. + * + * @param color The background color + */ + public void setColor(int color) { + mLayout.setBackgroundColor(color); + + // Display the color as a string on screen + String s = getResources().getString(R.string.display_color, color); + mText.setText(s); + } + +} diff --git a/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/Log.java b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/Log.java new file mode 100644 index 000000000..17503c568 --- /dev/null +++ b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/Log.java @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Helper class for a list (or tree) of LoggerNodes. + * + *When this is set as the head of the list, + * an instance of it can function as a drop-in replacement for {@link android.util.Log}. + * Most of the methods in this class server only to map a method call in Log to its equivalent + * in LogNode.
+ */ +public class Log { + // Grabbing the native values from Android's native logging facilities, + // to make for easy migration and interop. + public static final int NONE = -1; + public static final int VERBOSE = android.util.Log.VERBOSE; + public static final int DEBUG = android.util.Log.DEBUG; + public static final int INFO = android.util.Log.INFO; + public static final int WARN = android.util.Log.WARN; + public static final int ERROR = android.util.Log.ERROR; + public static final int ASSERT = android.util.Log.ASSERT; + + // Stores the beginning of the LogNode topology. + private static LogNode mLogNode; + + /** + * Returns the next LogNode in the linked list. + */ + public static LogNode getLogNode() { + return mLogNode; + } + + /** + * Sets the LogNode data will be sent to. + */ + public static void setLogNode(LogNode node) { + mLogNode = node; + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void println(int priority, String tag, String msg, Throwable tr) { + if (mLogNode != null) { + mLogNode.println(priority, tag, msg, tr); + } + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + */ + public static void println(int priority, String tag, String msg) { + println(priority, tag, msg, null); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void v(String tag, String msg, Throwable tr) { + println(VERBOSE, tag, msg, tr); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void v(String tag, String msg) { + v(tag, msg, null); + } + + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void d(String tag, String msg, Throwable tr) { + println(DEBUG, tag, msg, tr); + } + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void d(String tag, String msg) { + d(tag, msg, null); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void i(String tag, String msg, Throwable tr) { + println(INFO, tag, msg, tr); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void i(String tag, String msg) { + i(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, String msg, Throwable tr) { + println(WARN, tag, msg, tr); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void w(String tag, String msg) { + w(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, Throwable tr) { + w(tag, null, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void e(String tag, String msg, Throwable tr) { + println(ERROR, tag, msg, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void e(String tag, String msg) { + e(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, String msg, Throwable tr) { + println(ASSERT, tag, msg, tr); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void wtf(String tag, String msg) { + wtf(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, Throwable tr) { + wtf(tag, null, tr); + } +} diff --git a/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogFragment.java new file mode 100644 index 000000000..b302acd4b --- /dev/null +++ b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogFragment.java @@ -0,0 +1,109 @@ +/* +* Copyright 2013 The Android Open Source Project +* +* 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. +*/ +/* + * Copyright 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ScrollView; + +/** + * Simple fraggment which contains a LogView and uses is to output log data it receives + * through the LogNode interface. + */ +public class LogFragment extends Fragment { + + private LogView mLogView; + private ScrollView mScrollView; + + public LogFragment() {} + + public View inflateViews() { + mScrollView = new ScrollView(getActivity()); + ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mScrollView.setLayoutParams(scrollParams); + + mLogView = new LogView(getActivity()); + ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams); + logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + mLogView.setLayoutParams(logParams); + mLogView.setClickable(true); + mLogView.setFocusable(true); + mLogView.setTypeface(Typeface.MONOSPACE); + + // Want to set padding as 16 dips, setPadding takes pixels. Hooray math! + int paddingDips = 16; + double scale = getResources().getDisplayMetrics().density; + int paddingPixels = (int) ((paddingDips * (scale)) + .5); + mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels); + mLogView.setCompoundDrawablePadding(paddingPixels); + + mLogView.setGravity(Gravity.BOTTOM); + mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium); + + mScrollView.addView(mLogView); + return mScrollView; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View result = inflateViews(); + + mLogView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + mScrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + }); + return result; + } + + public LogView getLogView() { + return mLogView; + } +} \ No newline at end of file diff --git a/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogNode.java b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogNode.java new file mode 100644 index 000000000..bc37cabc0 --- /dev/null +++ b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogNode.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Basic interface for a logging system that can output to one or more targets. + * Note that in addition to classes that will output these logs in some format, + * one can also implement this interface over a filter and insert that in the chain, + * such that no targets further down see certain data, or see manipulated forms of the data. + * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data + * it received to HTML and sent it along to the next node in the chain, without printing it + * anywhere. + */ +public interface LogNode { + + /** + * Instructs first LogNode in the list to print the log data provided. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public void println(int priority, String tag, String msg, Throwable tr); + +} diff --git a/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogView.java b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogView.java new file mode 100644 index 000000000..c01542b91 --- /dev/null +++ b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogView.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.app.Activity; +import android.content.Context; +import android.util.*; +import android.widget.TextView; + +/** Simple TextView which is used to output log data received through the LogNode interface. +*/ +public class LogView extends TextView implements LogNode { + + public LogView(Context context) { + super(context); + } + + public LogView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LogView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Formats the log data and prints it out to the LogView. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + + + String priorityStr = null; + + // For the purposes of this View, we want to print the priority as readable text. + switch(priority) { + case android.util.Log.VERBOSE: + priorityStr = "VERBOSE"; + break; + case android.util.Log.DEBUG: + priorityStr = "DEBUG"; + break; + case android.util.Log.INFO: + priorityStr = "INFO"; + break; + case android.util.Log.WARN: + priorityStr = "WARN"; + break; + case android.util.Log.ERROR: + priorityStr = "ERROR"; + break; + case android.util.Log.ASSERT: + priorityStr = "ASSERT"; + break; + default: + break; + } + + // Handily, the Log class has a facility for converting a stack trace into a usable string. + String exceptionStr = null; + if (tr != null) { + exceptionStr = android.util.Log.getStackTraceString(tr); + } + + // Take the priority, tag, message, and exception, and concatenate as necessary + // into one usable line of text. + final StringBuilder outputBuilder = new StringBuilder(); + + String delimiter = "\t"; + appendIfNotNull(outputBuilder, priorityStr, delimiter); + appendIfNotNull(outputBuilder, tag, delimiter); + appendIfNotNull(outputBuilder, msg, delimiter); + appendIfNotNull(outputBuilder, exceptionStr, delimiter); + + // In case this was originally called from an AsyncTask or some other off-UI thread, + // make sure the update occurs within the UI thread. + ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() { + @Override + public void run() { + // Display the text we just generated within the LogView. + appendToLog(outputBuilder.toString()); + } + }))); + + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } + + public LogNode getNext() { + return mNext; + } + + public void setNext(LogNode node) { + mNext = node; + } + + /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since + * the logger takes so many arguments that might be null, this method helps cut out some of the + * agonizing tedium of writing the same 3 lines over and over. + * @param source StringBuilder containing the text to append to. + * @param addStr The String to append + * @param delimiter The String to separate the source and appended strings. A tab or comma, + * for instance. + * @return The fully concatenated String as a StringBuilder + */ + private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) { + if (addStr != null) { + if (addStr.length() == 0) { + delimiter = ""; + } + + return source.append(addStr).append(delimiter); + } + return source; + } + + // The next LogNode in the chain. + LogNode mNext; + + /** Outputs the string as a new line of log data in the LogView. */ + public void appendToLog(String s) { + append("\n" + s); + } + + +} diff --git a/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogWrapper.java new file mode 100644 index 000000000..16a9e7ba2 --- /dev/null +++ b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/LogWrapper.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.util.Log; + +/** + * Helper class which wraps Android's native Log utility in the Logger interface. This way + * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously. + */ +public class LogWrapper implements LogNode { + + // For piping: The next node to receive Log data after this one has done its work. + private LogNode mNext; + + /** + * Returns the next LogNode in the linked list. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + + /** + * Prints data out to the console using Android's native log mechanism. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + // There actually are log methods that don't take a msg parameter. For now, + // if that's the case, just convert null to the empty string and move on. + String useMsg = msg; + if (useMsg == null) { + useMsg = ""; + } + + // If an exeption was provided, convert that exception to a usable string and attach + // it to the end of the msg method. + if (tr != null) { + msg += "\n" + Log.getStackTraceString(tr); + } + + // This is functionally identical to Log.x(tag, useMsg); + // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg) + Log.println(priority, tag, useMsg); + + // If this isn't the last node in the chain, move things along. + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } +} diff --git a/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/MessageOnlyLogFilter.java new file mode 100644 index 000000000..19967dcd4 --- /dev/null +++ b/samples/browseable/BasicMediaRouter/src/com.example.android.common.logger/MessageOnlyLogFilter.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Simple {@link LogNode} filter, removes everything except the message. + * Useful for situations like on-screen log output where you don't want a lot of metadata displayed, + * just easy-to-read message updates as they're happening. + */ +public class MessageOnlyLogFilter implements LogNode { + + LogNode mNext; + + /** + * Takes the "next" LogNode as a parameter, to simplify chaining. + * + * @param next The next LogNode in the pipeline. + */ + public MessageOnlyLogFilter(LogNode next) { + mNext = next; + } + + public MessageOnlyLogFilter() { + } + + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + if (mNext != null) { + getNext().println(Log.NONE, null, msg, null); + } + } + + /** + * Returns the next LogNode in the chain. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + +} diff --git a/samples/browseable/BasicMultitouch/AndroidManifest.xml b/samples/browseable/BasicMultitouch/AndroidManifest.xml new file mode 100644 index 000000000..043345c19 --- /dev/null +++ b/samples/browseable/BasicMultitouch/AndroidManifest.xml @@ -0,0 +1,43 @@ + + + ++ +This samples demonstrates the use of MotionEvent properties to keep track of individual touches +across multiple touch events. +\n\nTouch the screen with multiple fingers to show that the pointer id +(also represented by a colour) does not change as new touch events are received.
+ * This is illustrated by a View ({@link TouchDisplayView}) that responds to + * touch events and draws coloured circles for each pointer, stores the last + * positions of this pointer and draws them. This example shows the relationship + * between MotionEvent indices, pointer identifiers and actions. + * + * @see android.view.MotionEvent + */ +public class MainActivity extends Activity { + TouchDisplayView mView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.layout_mainactivity); + } + +} diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.basicmultitouch/Pools.java b/samples/browseable/BasicMultitouch/src/com.example.android.basicmultitouch/Pools.java new file mode 100644 index 000000000..0eda0ee02 --- /dev/null +++ b/samples/browseable/BasicMultitouch/src/com.example.android.basicmultitouch/Pools.java @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * 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.example.android.basicmultitouch; + +/** + * Helper class for crating pools of objects. An example use looks like this: + *
+ * public class MyPooledClass {
+ *
+ * private static final SynchronizedPool sPool =
+ * new SynchronizedPool(10);
+ *
+ * public static MyPooledClass obtain() {
+ * MyPooledClass instance = sPool.acquire();
+ * return (instance != null) ? instance : new MyPooledClass();
+ * }
+ *
+ * public void recycle() {
+ * // Clear state if needed.
+ * sPool.release(this);
+ * }
+ *
+ * . . .
+ * }
+ *
+ *
+ * @hide
+ */
+public final class Pools {
+
+ /**
+ * Interface for managing a pool of objects.
+ *
+ * @param 1.0.
+ *
+ * @param canvas
+ * @param id
+ * @param data
+ */
+ protected void drawCircle(Canvas canvas, int id, TouchHistory data) {
+ // select the color based on the id
+ int color = COLORS[id % COLORS.length];
+ mCirclePaint.setColor(color);
+
+ /*
+ * Draw the circle, size scaled to its pressure. Pressure is clamped to
+ * 1.0 max to ensure proper drawing. (Reported pressure values can
+ * exceed 1.0, depending on the calibration of the touch screen).
+ */
+ float pressure = Math.min(data.pressure, 1f);
+ float radius = pressure * mCircleRadius;
+
+ canvas.drawCircle(data.x, (data.y) - (radius / 2f), radius,
+ mCirclePaint);
+
+ // draw all historical points with a lower alpha value
+ mCirclePaint.setAlpha(125);
+ for (int j = 0; j < data.history.length && j < data.historyCount; j++) {
+ PointF p = data.history[j];
+ canvas.drawCircle(p.x, p.y, mCircleHistoricalRadius, mCirclePaint);
+ }
+
+ // draw its label next to the main circle
+ canvas.drawText(data.label, data.x + radius, data.y
+ - radius, mTextPaint);
+ }
+
+}
diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/Log.java b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/Log.java
new file mode 100644
index 000000000..17503c568
--- /dev/null
+++ b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * When this is set as the head of the list, + * an instance of it can function as a drop-in replacement for {@link android.util.Log}. + * Most of the methods in this class server only to map a method call in Log to its equivalent + * in LogNode.
+ */ +public class Log { + // Grabbing the native values from Android's native logging facilities, + // to make for easy migration and interop. + public static final int NONE = -1; + public static final int VERBOSE = android.util.Log.VERBOSE; + public static final int DEBUG = android.util.Log.DEBUG; + public static final int INFO = android.util.Log.INFO; + public static final int WARN = android.util.Log.WARN; + public static final int ERROR = android.util.Log.ERROR; + public static final int ASSERT = android.util.Log.ASSERT; + + // Stores the beginning of the LogNode topology. + private static LogNode mLogNode; + + /** + * Returns the next LogNode in the linked list. + */ + public static LogNode getLogNode() { + return mLogNode; + } + + /** + * Sets the LogNode data will be sent to. + */ + public static void setLogNode(LogNode node) { + mLogNode = node; + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void println(int priority, String tag, String msg, Throwable tr) { + if (mLogNode != null) { + mLogNode.println(priority, tag, msg, tr); + } + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + */ + public static void println(int priority, String tag, String msg) { + println(priority, tag, msg, null); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void v(String tag, String msg, Throwable tr) { + println(VERBOSE, tag, msg, tr); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void v(String tag, String msg) { + v(tag, msg, null); + } + + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void d(String tag, String msg, Throwable tr) { + println(DEBUG, tag, msg, tr); + } + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void d(String tag, String msg) { + d(tag, msg, null); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void i(String tag, String msg, Throwable tr) { + println(INFO, tag, msg, tr); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void i(String tag, String msg) { + i(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, String msg, Throwable tr) { + println(WARN, tag, msg, tr); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void w(String tag, String msg) { + w(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, Throwable tr) { + w(tag, null, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void e(String tag, String msg, Throwable tr) { + println(ERROR, tag, msg, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void e(String tag, String msg) { + e(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, String msg, Throwable tr) { + println(ASSERT, tag, msg, tr); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void wtf(String tag, String msg) { + wtf(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, Throwable tr) { + wtf(tag, null, tr); + } +} diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogFragment.java new file mode 100644 index 000000000..b302acd4b --- /dev/null +++ b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogFragment.java @@ -0,0 +1,109 @@ +/* +* Copyright 2013 The Android Open Source Project +* +* 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. +*/ +/* + * Copyright 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ScrollView; + +/** + * Simple fraggment which contains a LogView and uses is to output log data it receives + * through the LogNode interface. + */ +public class LogFragment extends Fragment { + + private LogView mLogView; + private ScrollView mScrollView; + + public LogFragment() {} + + public View inflateViews() { + mScrollView = new ScrollView(getActivity()); + ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mScrollView.setLayoutParams(scrollParams); + + mLogView = new LogView(getActivity()); + ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams); + logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + mLogView.setLayoutParams(logParams); + mLogView.setClickable(true); + mLogView.setFocusable(true); + mLogView.setTypeface(Typeface.MONOSPACE); + + // Want to set padding as 16 dips, setPadding takes pixels. Hooray math! + int paddingDips = 16; + double scale = getResources().getDisplayMetrics().density; + int paddingPixels = (int) ((paddingDips * (scale)) + .5); + mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels); + mLogView.setCompoundDrawablePadding(paddingPixels); + + mLogView.setGravity(Gravity.BOTTOM); + mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium); + + mScrollView.addView(mLogView); + return mScrollView; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View result = inflateViews(); + + mLogView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + mScrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + }); + return result; + } + + public LogView getLogView() { + return mLogView; + } +} \ No newline at end of file diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogNode.java b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogNode.java new file mode 100644 index 000000000..bc37cabc0 --- /dev/null +++ b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogNode.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Basic interface for a logging system that can output to one or more targets. + * Note that in addition to classes that will output these logs in some format, + * one can also implement this interface over a filter and insert that in the chain, + * such that no targets further down see certain data, or see manipulated forms of the data. + * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data + * it received to HTML and sent it along to the next node in the chain, without printing it + * anywhere. + */ +public interface LogNode { + + /** + * Instructs first LogNode in the list to print the log data provided. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public void println(int priority, String tag, String msg, Throwable tr); + +} diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogView.java b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogView.java new file mode 100644 index 000000000..c01542b91 --- /dev/null +++ b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogView.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.app.Activity; +import android.content.Context; +import android.util.*; +import android.widget.TextView; + +/** Simple TextView which is used to output log data received through the LogNode interface. +*/ +public class LogView extends TextView implements LogNode { + + public LogView(Context context) { + super(context); + } + + public LogView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LogView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Formats the log data and prints it out to the LogView. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + + + String priorityStr = null; + + // For the purposes of this View, we want to print the priority as readable text. + switch(priority) { + case android.util.Log.VERBOSE: + priorityStr = "VERBOSE"; + break; + case android.util.Log.DEBUG: + priorityStr = "DEBUG"; + break; + case android.util.Log.INFO: + priorityStr = "INFO"; + break; + case android.util.Log.WARN: + priorityStr = "WARN"; + break; + case android.util.Log.ERROR: + priorityStr = "ERROR"; + break; + case android.util.Log.ASSERT: + priorityStr = "ASSERT"; + break; + default: + break; + } + + // Handily, the Log class has a facility for converting a stack trace into a usable string. + String exceptionStr = null; + if (tr != null) { + exceptionStr = android.util.Log.getStackTraceString(tr); + } + + // Take the priority, tag, message, and exception, and concatenate as necessary + // into one usable line of text. + final StringBuilder outputBuilder = new StringBuilder(); + + String delimiter = "\t"; + appendIfNotNull(outputBuilder, priorityStr, delimiter); + appendIfNotNull(outputBuilder, tag, delimiter); + appendIfNotNull(outputBuilder, msg, delimiter); + appendIfNotNull(outputBuilder, exceptionStr, delimiter); + + // In case this was originally called from an AsyncTask or some other off-UI thread, + // make sure the update occurs within the UI thread. + ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() { + @Override + public void run() { + // Display the text we just generated within the LogView. + appendToLog(outputBuilder.toString()); + } + }))); + + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } + + public LogNode getNext() { + return mNext; + } + + public void setNext(LogNode node) { + mNext = node; + } + + /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since + * the logger takes so many arguments that might be null, this method helps cut out some of the + * agonizing tedium of writing the same 3 lines over and over. + * @param source StringBuilder containing the text to append to. + * @param addStr The String to append + * @param delimiter The String to separate the source and appended strings. A tab or comma, + * for instance. + * @return The fully concatenated String as a StringBuilder + */ + private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) { + if (addStr != null) { + if (addStr.length() == 0) { + delimiter = ""; + } + + return source.append(addStr).append(delimiter); + } + return source; + } + + // The next LogNode in the chain. + LogNode mNext; + + /** Outputs the string as a new line of log data in the LogView. */ + public void appendToLog(String s) { + append("\n" + s); + } + + +} diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogWrapper.java new file mode 100644 index 000000000..16a9e7ba2 --- /dev/null +++ b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/LogWrapper.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.util.Log; + +/** + * Helper class which wraps Android's native Log utility in the Logger interface. This way + * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously. + */ +public class LogWrapper implements LogNode { + + // For piping: The next node to receive Log data after this one has done its work. + private LogNode mNext; + + /** + * Returns the next LogNode in the linked list. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + + /** + * Prints data out to the console using Android's native log mechanism. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + // There actually are log methods that don't take a msg parameter. For now, + // if that's the case, just convert null to the empty string and move on. + String useMsg = msg; + if (useMsg == null) { + useMsg = ""; + } + + // If an exeption was provided, convert that exception to a usable string and attach + // it to the end of the msg method. + if (tr != null) { + msg += "\n" + Log.getStackTraceString(tr); + } + + // This is functionally identical to Log.x(tag, useMsg); + // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg) + Log.println(priority, tag, useMsg); + + // If this isn't the last node in the chain, move things along. + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } +} diff --git a/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/MessageOnlyLogFilter.java new file mode 100644 index 000000000..19967dcd4 --- /dev/null +++ b/samples/browseable/BasicMultitouch/src/com.example.android.common.logger/MessageOnlyLogFilter.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Simple {@link LogNode} filter, removes everything except the message. + * Useful for situations like on-screen log output where you don't want a lot of metadata displayed, + * just easy-to-read message updates as they're happening. + */ +public class MessageOnlyLogFilter implements LogNode { + + LogNode mNext; + + /** + * Takes the "next" LogNode as a parameter, to simplify chaining. + * + * @param next The next LogNode in the pipeline. + */ + public MessageOnlyLogFilter(LogNode next) { + mNext = next; + } + + public MessageOnlyLogFilter() { + } + + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + if (mNext != null) { + getNext().println(Log.NONE, null, msg, null); + } + } + + /** + * Returns the next LogNode in the chain. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + +} diff --git a/samples/browseable/BasicNetworking/AndroidManifest.xml b/samples/browseable/BasicNetworking/AndroidManifest.xml new file mode 100644 index 000000000..48bfeac46 --- /dev/null +++ b/samples/browseable/BasicNetworking/AndroidManifest.xml @@ -0,0 +1,44 @@ + + ++ + This sample demonstrates how to use the ConnectivityManager to determine if you have + a network connection, and if so, what type of connection it is. + \n\nA "NetworkInfo" object is retrieved from the ConnectivityManager, which contains information + on the active connection, and then the connection type is printed to an on-screen console. + +
diff --git a/samples/browseable/BasicNetworking/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicNetworking/res/drawable-hdpi/ic_launcher.png new file mode 100755 index 000000000..22ce60611 Binary files /dev/null and b/samples/browseable/BasicNetworking/res/drawable-hdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicNetworking/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicNetworking/res/drawable-hdpi/tile.9.png new file mode 100644 index 000000000..135862883 Binary files /dev/null and b/samples/browseable/BasicNetworking/res/drawable-hdpi/tile.9.png differ diff --git a/samples/browseable/BasicNetworking/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicNetworking/res/drawable-mdpi/ic_launcher.png new file mode 100755 index 000000000..f21e17b65 Binary files /dev/null and b/samples/browseable/BasicNetworking/res/drawable-mdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicNetworking/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicNetworking/res/drawable-xhdpi/ic_launcher.png new file mode 100755 index 000000000..64b805902 Binary files /dev/null and b/samples/browseable/BasicNetworking/res/drawable-xhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicNetworking/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicNetworking/res/drawable-xxhdpi/ic_launcher.png new file mode 100755 index 000000000..6b4434a87 Binary files /dev/null and b/samples/browseable/BasicNetworking/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicNetworking/res/layout/activity_main.xml b/samples/browseable/BasicNetworking/res/layout/activity_main.xml new file mode 100755 index 000000000..be1aa49d9 --- /dev/null +++ b/samples/browseable/BasicNetworking/res/layout/activity_main.xml @@ -0,0 +1,36 @@ + + +When this is set as the head of the list, + * an instance of it can function as a drop-in replacement for {@link android.util.Log}. + * Most of the methods in this class server only to map a method call in Log to its equivalent + * in LogNode.
+ */ +public class Log { + // Grabbing the native values from Android's native logging facilities, + // to make for easy migration and interop. + public static final int NONE = -1; + public static final int VERBOSE = android.util.Log.VERBOSE; + public static final int DEBUG = android.util.Log.DEBUG; + public static final int INFO = android.util.Log.INFO; + public static final int WARN = android.util.Log.WARN; + public static final int ERROR = android.util.Log.ERROR; + public static final int ASSERT = android.util.Log.ASSERT; + + // Stores the beginning of the LogNode topology. + private static LogNode mLogNode; + + /** + * Returns the next LogNode in the linked list. + */ + public static LogNode getLogNode() { + return mLogNode; + } + + /** + * Sets the LogNode data will be sent to. + */ + public static void setLogNode(LogNode node) { + mLogNode = node; + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void println(int priority, String tag, String msg, Throwable tr) { + if (mLogNode != null) { + mLogNode.println(priority, tag, msg, tr); + } + } + + /** + * Instructs the LogNode to print the log data provided. Other LogNodes can + * be chained to the end of the LogNode as desired. + * + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + */ + public static void println(int priority, String tag, String msg) { + println(priority, tag, msg, null); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void v(String tag, String msg, Throwable tr) { + println(VERBOSE, tag, msg, tr); + } + + /** + * Prints a message at VERBOSE priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void v(String tag, String msg) { + v(tag, msg, null); + } + + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void d(String tag, String msg, Throwable tr) { + println(DEBUG, tag, msg, tr); + } + + /** + * Prints a message at DEBUG priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void d(String tag, String msg) { + d(tag, msg, null); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void i(String tag, String msg, Throwable tr) { + println(INFO, tag, msg, tr); + } + + /** + * Prints a message at INFO priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void i(String tag, String msg) { + i(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, String msg, Throwable tr) { + println(WARN, tag, msg, tr); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void w(String tag, String msg) { + w(tag, msg, null); + } + + /** + * Prints a message at WARN priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void w(String tag, Throwable tr) { + w(tag, null, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void e(String tag, String msg, Throwable tr) { + println(ERROR, tag, msg, tr); + } + + /** + * Prints a message at ERROR priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void e(String tag, String msg) { + e(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, String msg, Throwable tr) { + println(ASSERT, tag, msg, tr); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. + */ + public static void wtf(String tag, String msg) { + wtf(tag, msg, null); + } + + /** + * Prints a message at ASSERT priority. + * + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public static void wtf(String tag, Throwable tr) { + wtf(tag, null, tr); + } +} diff --git a/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogFragment.java b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogFragment.java new file mode 100644 index 000000000..b302acd4b --- /dev/null +++ b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogFragment.java @@ -0,0 +1,109 @@ +/* +* Copyright 2013 The Android Open Source Project +* +* 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. +*/ +/* + * Copyright 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.graphics.Typeface; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ScrollView; + +/** + * Simple fraggment which contains a LogView and uses is to output log data it receives + * through the LogNode interface. + */ +public class LogFragment extends Fragment { + + private LogView mLogView; + private ScrollView mScrollView; + + public LogFragment() {} + + public View inflateViews() { + mScrollView = new ScrollView(getActivity()); + ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT); + mScrollView.setLayoutParams(scrollParams); + + mLogView = new LogView(getActivity()); + ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams); + logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; + mLogView.setLayoutParams(logParams); + mLogView.setClickable(true); + mLogView.setFocusable(true); + mLogView.setTypeface(Typeface.MONOSPACE); + + // Want to set padding as 16 dips, setPadding takes pixels. Hooray math! + int paddingDips = 16; + double scale = getResources().getDisplayMetrics().density; + int paddingPixels = (int) ((paddingDips * (scale)) + .5); + mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels); + mLogView.setCompoundDrawablePadding(paddingPixels); + + mLogView.setGravity(Gravity.BOTTOM); + mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium); + + mScrollView.addView(mLogView); + return mScrollView; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + View result = inflateViews(); + + mLogView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) {} + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) {} + + @Override + public void afterTextChanged(Editable s) { + mScrollView.fullScroll(ScrollView.FOCUS_DOWN); + } + }); + return result; + } + + public LogView getLogView() { + return mLogView; + } +} \ No newline at end of file diff --git a/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogNode.java b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogNode.java new file mode 100644 index 000000000..bc37cabc0 --- /dev/null +++ b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogNode.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Basic interface for a logging system that can output to one or more targets. + * Note that in addition to classes that will output these logs in some format, + * one can also implement this interface over a filter and insert that in the chain, + * such that no targets further down see certain data, or see manipulated forms of the data. + * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data + * it received to HTML and sent it along to the next node in the chain, without printing it + * anywhere. + */ +public interface LogNode { + + /** + * Instructs first LogNode in the list to print the log data provided. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + public void println(int priority, String tag, String msg, Throwable tr); + +} diff --git a/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogView.java b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogView.java new file mode 100644 index 000000000..c01542b91 --- /dev/null +++ b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogView.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.app.Activity; +import android.content.Context; +import android.util.*; +import android.widget.TextView; + +/** Simple TextView which is used to output log data received through the LogNode interface. +*/ +public class LogView extends TextView implements LogNode { + + public LogView(Context context) { + super(context); + } + + public LogView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public LogView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Formats the log data and prints it out to the LogView. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + + + String priorityStr = null; + + // For the purposes of this View, we want to print the priority as readable text. + switch(priority) { + case android.util.Log.VERBOSE: + priorityStr = "VERBOSE"; + break; + case android.util.Log.DEBUG: + priorityStr = "DEBUG"; + break; + case android.util.Log.INFO: + priorityStr = "INFO"; + break; + case android.util.Log.WARN: + priorityStr = "WARN"; + break; + case android.util.Log.ERROR: + priorityStr = "ERROR"; + break; + case android.util.Log.ASSERT: + priorityStr = "ASSERT"; + break; + default: + break; + } + + // Handily, the Log class has a facility for converting a stack trace into a usable string. + String exceptionStr = null; + if (tr != null) { + exceptionStr = android.util.Log.getStackTraceString(tr); + } + + // Take the priority, tag, message, and exception, and concatenate as necessary + // into one usable line of text. + final StringBuilder outputBuilder = new StringBuilder(); + + String delimiter = "\t"; + appendIfNotNull(outputBuilder, priorityStr, delimiter); + appendIfNotNull(outputBuilder, tag, delimiter); + appendIfNotNull(outputBuilder, msg, delimiter); + appendIfNotNull(outputBuilder, exceptionStr, delimiter); + + // In case this was originally called from an AsyncTask or some other off-UI thread, + // make sure the update occurs within the UI thread. + ((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() { + @Override + public void run() { + // Display the text we just generated within the LogView. + appendToLog(outputBuilder.toString()); + } + }))); + + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } + + public LogNode getNext() { + return mNext; + } + + public void setNext(LogNode node) { + mNext = node; + } + + /** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since + * the logger takes so many arguments that might be null, this method helps cut out some of the + * agonizing tedium of writing the same 3 lines over and over. + * @param source StringBuilder containing the text to append to. + * @param addStr The String to append + * @param delimiter The String to separate the source and appended strings. A tab or comma, + * for instance. + * @return The fully concatenated String as a StringBuilder + */ + private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) { + if (addStr != null) { + if (addStr.length() == 0) { + delimiter = ""; + } + + return source.append(addStr).append(delimiter); + } + return source; + } + + // The next LogNode in the chain. + LogNode mNext; + + /** Outputs the string as a new line of log data in the LogView. */ + public void appendToLog(String s) { + append("\n" + s); + } + + +} diff --git a/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogWrapper.java b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogWrapper.java new file mode 100644 index 000000000..16a9e7ba2 --- /dev/null +++ b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/LogWrapper.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * 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.example.android.common.logger; + +import android.util.Log; + +/** + * Helper class which wraps Android's native Log utility in the Logger interface. This way + * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously. + */ +public class LogWrapper implements LogNode { + + // For piping: The next node to receive Log data after this one has done its work. + private LogNode mNext; + + /** + * Returns the next LogNode in the linked list. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + + /** + * Prints data out to the console using Android's native log mechanism. + * @param priority Log level of the data being logged. Verbose, Error, etc. + * @param tag Tag for for the log data. Can be used to organize log statements. + * @param msg The actual message to be logged. The actual message to be logged. + * @param tr If an exception was thrown, this can be sent along for the logging facilities + * to extract and print useful information. + */ + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + // There actually are log methods that don't take a msg parameter. For now, + // if that's the case, just convert null to the empty string and move on. + String useMsg = msg; + if (useMsg == null) { + useMsg = ""; + } + + // If an exeption was provided, convert that exception to a usable string and attach + // it to the end of the msg method. + if (tr != null) { + msg += "\n" + Log.getStackTraceString(tr); + } + + // This is functionally identical to Log.x(tag, useMsg); + // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg) + Log.println(priority, tag, useMsg); + + // If this isn't the last node in the chain, move things along. + if (mNext != null) { + mNext.println(priority, tag, msg, tr); + } + } +} diff --git a/samples/browseable/BasicNetworking/src/com.example.android.common.logger/MessageOnlyLogFilter.java b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/MessageOnlyLogFilter.java new file mode 100644 index 000000000..19967dcd4 --- /dev/null +++ b/samples/browseable/BasicNetworking/src/com.example.android.common.logger/MessageOnlyLogFilter.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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.example.android.common.logger; + +/** + * Simple {@link LogNode} filter, removes everything except the message. + * Useful for situations like on-screen log output where you don't want a lot of metadata displayed, + * just easy-to-read message updates as they're happening. + */ +public class MessageOnlyLogFilter implements LogNode { + + LogNode mNext; + + /** + * Takes the "next" LogNode as a parameter, to simplify chaining. + * + * @param next The next LogNode in the pipeline. + */ + public MessageOnlyLogFilter(LogNode next) { + mNext = next; + } + + public MessageOnlyLogFilter() { + } + + @Override + public void println(int priority, String tag, String msg, Throwable tr) { + if (mNext != null) { + getNext().println(Log.NONE, null, msg, null); + } + } + + /** + * Returns the next LogNode in the chain. + */ + public LogNode getNext() { + return mNext; + } + + /** + * Sets the LogNode data will be sent to.. + */ + public void setNext(LogNode node) { + mNext = node; + } + +} diff --git a/samples/browseable/BasicNotifications/AndroidManifest.xml b/samples/browseable/BasicNotifications/AndroidManifest.xml new file mode 100644 index 000000000..1e37d0bf6 --- /dev/null +++ b/samples/browseable/BasicNotifications/AndroidManifest.xml @@ -0,0 +1,42 @@ + + + ++ + This sample demonstrates how to display events in the system\'s notification bar. The + NotificationCompat API is used for compatibility with older devices, running Android + 2.2 (Froyo) or newer. + +
diff --git a/samples/browseable/BasicNotifications/res/drawable-hdpi-v11/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-hdpi-v11/ic_stat_notification.png new file mode 100644 index 000000000..604d3a394 Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-hdpi-v11/ic_stat_notification.png differ diff --git a/samples/browseable/BasicNotifications/res/drawable-hdpi-v9/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-hdpi-v9/ic_stat_notification.png new file mode 100644 index 000000000..5c86ffd03 Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-hdpi-v9/ic_stat_notification.png differ diff --git a/samples/browseable/BasicNotifications/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicNotifications/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..743382b99 Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-hdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicNotifications/res/drawable-hdpi/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-hdpi/ic_stat_notification.png new file mode 100644 index 000000000..f39c3b337 Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-hdpi/ic_stat_notification.png differ diff --git a/samples/browseable/BasicNotifications/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicNotifications/res/drawable-hdpi/tile.9.png new file mode 100644 index 000000000..135862883 Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-hdpi/tile.9.png differ diff --git a/samples/browseable/BasicNotifications/res/drawable-ldpi-v11/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-ldpi-v11/ic_stat_notification.png new file mode 100644 index 000000000..b919a32e0 Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-ldpi-v11/ic_stat_notification.png differ diff --git a/samples/browseable/BasicNotifications/res/drawable-ldpi-v9/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-ldpi-v9/ic_stat_notification.png new file mode 100644 index 000000000..1ce3e7e88 Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-ldpi-v9/ic_stat_notification.png differ diff --git a/samples/browseable/BasicNotifications/res/drawable-mdpi-v11/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-mdpi-v11/ic_stat_notification.png new file mode 100644 index 000000000..3f4d4a6f1 Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-mdpi-v11/ic_stat_notification.png differ diff --git a/samples/browseable/BasicNotifications/res/drawable-mdpi-v9/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-mdpi-v9/ic_stat_notification.png new file mode 100644 index 000000000..1dbd17c3e Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-mdpi-v9/ic_stat_notification.png differ diff --git a/samples/browseable/BasicNotifications/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicNotifications/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..46a51a45d Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-mdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicNotifications/res/drawable-mdpi/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-mdpi/ic_stat_notification.png new file mode 100644 index 000000000..eafbbd12c Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-mdpi/ic_stat_notification.png differ diff --git a/samples/browseable/BasicNotifications/res/drawable-xhdpi-v11/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-xhdpi-v11/ic_stat_notification.png new file mode 100644 index 000000000..d2317d7ba Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-xhdpi-v11/ic_stat_notification.png differ diff --git a/samples/browseable/BasicNotifications/res/drawable-xhdpi-v9/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-xhdpi-v9/ic_stat_notification.png new file mode 100644 index 000000000..7011de877 Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-xhdpi-v9/ic_stat_notification.png differ diff --git a/samples/browseable/BasicNotifications/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicNotifications/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..f97cef381 Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-xhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicNotifications/res/drawable-xhdpi/ic_stat_notification.png b/samples/browseable/BasicNotifications/res/drawable-xhdpi/ic_stat_notification.png new file mode 100644 index 000000000..1f0d6523e Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-xhdpi/ic_stat_notification.png differ diff --git a/samples/browseable/BasicNotifications/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicNotifications/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..17fa1306a Binary files /dev/null and b/samples/browseable/BasicNotifications/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicNotifications/res/layout/activity_main.xml b/samples/browseable/BasicNotifications/res/layout/activity_main.xml new file mode 100755 index 000000000..be1aa49d9 --- /dev/null +++ b/samples/browseable/BasicNotifications/res/layout/activity_main.xml @@ -0,0 +1,36 @@ + + ++ + This sample demonstrates using SyncAdapter to fetch background data for an app that + doesn\'t require a user-visible account type or 2-way synchronization. + + \n\nThis sample periodically downloads the feed from the Android Developer Blog and + caches the data in a content provider. At runtime, the cached feed data is displayed + inside a ListView. + +
diff --git a/samples/browseable/BasicSyncAdapter/res/drawable-hdpi/ic_launcher.png b/samples/browseable/BasicSyncAdapter/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 000000000..a0f7005a3 Binary files /dev/null and b/samples/browseable/BasicSyncAdapter/res/drawable-hdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicSyncAdapter/res/drawable-hdpi/tile.9.png b/samples/browseable/BasicSyncAdapter/res/drawable-hdpi/tile.9.png new file mode 100644 index 000000000..135862883 Binary files /dev/null and b/samples/browseable/BasicSyncAdapter/res/drawable-hdpi/tile.9.png differ diff --git a/samples/browseable/BasicSyncAdapter/res/drawable-mdpi/ic_launcher.png b/samples/browseable/BasicSyncAdapter/res/drawable-mdpi/ic_launcher.png new file mode 100644 index 000000000..a085462c2 Binary files /dev/null and b/samples/browseable/BasicSyncAdapter/res/drawable-mdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicSyncAdapter/res/drawable-xhdpi/ic_action_refresh.png b/samples/browseable/BasicSyncAdapter/res/drawable-xhdpi/ic_action_refresh.png new file mode 100644 index 000000000..4f5d2558f Binary files /dev/null and b/samples/browseable/BasicSyncAdapter/res/drawable-xhdpi/ic_action_refresh.png differ diff --git a/samples/browseable/BasicSyncAdapter/res/drawable-xhdpi/ic_launcher.png b/samples/browseable/BasicSyncAdapter/res/drawable-xhdpi/ic_launcher.png new file mode 100644 index 000000000..4f78eb846 Binary files /dev/null and b/samples/browseable/BasicSyncAdapter/res/drawable-xhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicSyncAdapter/res/drawable-xxhdpi/ic_launcher.png b/samples/browseable/BasicSyncAdapter/res/drawable-xxhdpi/ic_launcher.png new file mode 100644 index 000000000..b198ee3e9 Binary files /dev/null and b/samples/browseable/BasicSyncAdapter/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/samples/browseable/BasicSyncAdapter/res/layout/actionbar_indeterminate_progress.xml b/samples/browseable/BasicSyncAdapter/res/layout/actionbar_indeterminate_progress.xml new file mode 100644 index 000000000..b25401306 --- /dev/null +++ b/samples/browseable/BasicSyncAdapter/res/layout/actionbar_indeterminate_progress.xml @@ -0,0 +1,25 @@ + +Database access is mediated by a content provider, specified in + * {@link com.example.android.basicsyncadapter.provider.FeedProvider}. This content + * provider is + * automatically populated by {@link SyncService}. + * + *
Selecting an item from the displayed list displays the article in the default browser. + * + *
If the content provider doesn't return any data, then the first sync hasn't run yet. This sync + * adapter assumes data exists in the provider once a sync has run. If your app doesn't work like + * this, you should add a flag that notes if a sync has run, so you can differentiate between "no + * available data" and "no initial sync", and display this in the UI. + * + *
The ActionBar displays a "Refresh" button. When the user clicks "Refresh", the sync adapter
+ * runs immediately. An indeterminate ProgressBar element is displayed, showing that the sync is
+ * occurring.
+ */
+public class EntryListFragment extends ListFragment
+ implements LoaderManager.LoaderCallbacks This allows us to delete our SyncObserver once the application is no longer in the
+ * foreground.
+ */
+ private Object mSyncObserverHandle;
+
+ /**
+ * Options menu used to populate ActionBar.
+ */
+ private Menu mOptionsMenu;
+
+ /**
+ * Projection for querying the content provider.
+ */
+ private static final String[] PROJECTION = new String[]{
+ FeedContract.Entry._ID,
+ FeedContract.Entry.COLUMN_NAME_TITLE,
+ FeedContract.Entry.COLUMN_NAME_LINK,
+ FeedContract.Entry.COLUMN_NAME_PUBLISHED
+ };
+
+ // Column indexes. The index of a column in the Cursor is the same as its relative position in
+ // the projection.
+ /** Column index for _ID */
+ private static final int COLUMN_ID = 0;
+ /** Column index for title */
+ private static final int COLUMN_TITLE = 1;
+ /** Column index for link */
+ private static final int COLUMN_URL_STRING = 2;
+ /** Column index for published */
+ private static final int COLUMN_PUBLISHED = 3;
+
+ /**
+ * List of Cursor columns to read from when preparing an adapter to populate the ListView.
+ */
+ private static final String[] FROM_COLUMNS = new String[]{
+ FeedContract.Entry.COLUMN_NAME_TITLE,
+ FeedContract.Entry.COLUMN_NAME_PUBLISHED
+ };
+
+ /**
+ * List of Views which will be populated by Cursor data.
+ */
+ private static final int[] TO_FIELDS = new int[]{
+ android.R.id.text1,
+ android.R.id.text2};
+
+ /**
+ * Mandatory empty constructor for the fragment manager to instantiate the
+ * fragment (e.g. upon screen orientation changes).
+ */
+ public EntryListFragment() {}
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setHasOptionsMenu(true);
+ }
+
+ /**
+ * Create SyncAccount at launch, if needed.
+ *
+ * This will create a new account with the system for our application, register our
+ * {@link SyncService} with it, and establish a sync schedule.
+ */
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+
+ // Create account, if needed
+ SyncUtils.CreateSyncAccount(activity);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+
+ mAdapter = new SimpleCursorAdapter(
+ getActivity(), // Current context
+ android.R.layout.simple_list_item_activated_2, // Layout for individual rows
+ null, // Cursor
+ FROM_COLUMNS, // Cursor columns to use
+ TO_FIELDS, // Layout fields to use
+ 0 // No flags
+ );
+ mAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
+ @Override
+ public boolean setViewValue(View view, Cursor cursor, int i) {
+ if (i == COLUMN_PUBLISHED) {
+ // Convert timestamp to human-readable date
+ Time t = new Time();
+ t.set(cursor.getLong(i));
+ ((TextView) view).setText(t.format("%Y-%m-%d %H:%M"));
+ return true;
+ } else {
+ // Let SimpleCursorAdapter handle other fields automatically
+ return false;
+ }
+ }
+ });
+ setListAdapter(mAdapter);
+ setEmptyText(getText(R.string.loading));
+ getLoaderManager().initLoader(0, null, this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mSyncStatusObserver.onStatusChanged(0);
+
+ // Watch for sync state changes
+ final int mask = ContentResolver.SYNC_OBSERVER_TYPE_PENDING |
+ ContentResolver.SYNC_OBSERVER_TYPE_ACTIVE;
+ mSyncObserverHandle = ContentResolver.addStatusChangeListener(mask, mSyncStatusObserver);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ if (mSyncObserverHandle != null) {
+ ContentResolver.removeStatusChangeListener(mSyncObserverHandle);
+ mSyncObserverHandle = null;
+ }
+ }
+
+ /**
+ * Query the content provider for data.
+ *
+ * Loaders do queries in a background thread. They also provide a ContentObserver that is
+ * triggered when data in the content provider changes. When the sync adapter updates the
+ * content provider, the ContentObserver responds by resetting the loader and then reloading
+ * it.
+ */
+ @Override
+ public Loader This class is instantiated in {@link SyncService}, which also binds SyncAdapter to the system.
+ * SyncAdapter should only be initialized in SyncService, never anywhere else.
+ *
+ * The system calls onPerformSync() via an RPC call through the IBinder object supplied by
+ * SyncService.
+ */
+class SyncAdapter extends AbstractThreadedSyncAdapter {
+ public static final String TAG = "SyncAdapter";
+
+ /**
+ * URL to fetch content from during a sync.
+ *
+ * This points to the Android Developers Blog. (Side note: We highly recommend reading the
+ * Android Developer Blog to stay up to date on the latest Android platform developments!)
+ */
+ private static final String FEED_URL = "http://android-developers.blogspot.com/atom.xml";
+
+ /**
+ * Network connection timeout, in milliseconds.
+ */
+ private static final int NET_CONNECT_TIMEOUT_MILLIS = 15000; // 15 seconds
+
+ /**
+ * Network read timeout, in milliseconds.
+ */
+ private static final int NET_READ_TIMEOUT_MILLIS = 10000; // 10 seconds
+
+ /**
+ * Content resolver, for performing database operations.
+ */
+ private final ContentResolver mContentResolver;
+
+ /**
+ * Project used when querying content provider. Returns all known fields.
+ */
+ private static final String[] PROJECTION = new String[] {
+ FeedContract.Entry._ID,
+ FeedContract.Entry.COLUMN_NAME_ENTRY_ID,
+ FeedContract.Entry.COLUMN_NAME_TITLE,
+ FeedContract.Entry.COLUMN_NAME_LINK,
+ FeedContract.Entry.COLUMN_NAME_PUBLISHED};
+
+ // Constants representing column positions from PROJECTION.
+ public static final int COLUMN_ID = 0;
+ public static final int COLUMN_ENTRY_ID = 1;
+ public static final int COLUMN_TITLE = 2;
+ public static final int COLUMN_LINK = 3;
+ public static final int COLUMN_PUBLISHED = 4;
+
+ /**
+ * Constructor. Obtains handle to content resolver for later use.
+ */
+ public SyncAdapter(Context context, boolean autoInitialize) {
+ super(context, autoInitialize);
+ mContentResolver = context.getContentResolver();
+ }
+
+ /**
+ * Constructor. Obtains handle to content resolver for later use.
+ */
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ public SyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {
+ super(context, autoInitialize, allowParallelSyncs);
+ mContentResolver = context.getContentResolver();
+ }
+
+ /**
+ * Called by the Android system in response to a request to run the sync adapter. The work
+ * required to read data from the network, parse it, and store it in the content provider is
+ * done here. Extending AbstractThreadedSyncAdapter ensures that all methods within SyncAdapter
+ * run on a background thread. For this reason, blocking I/O and other long-running tasks can be
+ * run in situ, and you don't have to set up a separate thread for them.
+ .
+ *
+ * This is where we actually perform any work required to perform a sync.
+ * {@link android.content.AbstractThreadedSyncAdapter} guarantees that this will be called on a non-UI thread,
+ * so it is safe to peform blocking I/O here.
+ *
+ * The syncResult argument allows you to pass information back to the method that triggered
+ * the sync.
+ */
+ @Override
+ public void onPerformSync(Account account, Bundle extras, String authority,
+ ContentProviderClient provider, SyncResult syncResult) {
+ Log.i(TAG, "Beginning network synchronization");
+ try {
+ final URL location = new URL(FEED_URL);
+ InputStream stream = null;
+
+ try {
+ Log.i(TAG, "Streaming data from network: " + location);
+ stream = downloadUrl(location);
+ updateLocalFeedData(stream, syncResult);
+ // Makes sure that the InputStream is closed after the app is
+ // finished using it.
+ } finally {
+ if (stream != null) {
+ stream.close();
+ }
+ }
+ } catch (MalformedURLException e) {
+ Log.e(TAG, "Feed URL is malformed", e);
+ syncResult.stats.numParseExceptions++;
+ return;
+ } catch (IOException e) {
+ Log.e(TAG, "Error reading from network: " + e.toString());
+ syncResult.stats.numIoExceptions++;
+ return;
+ } catch (XmlPullParserException e) {
+ Log.e(TAG, "Error parsing feed: " + e.toString());
+ syncResult.stats.numParseExceptions++;
+ return;
+ } catch (ParseException e) {
+ Log.e(TAG, "Error parsing feed: " + e.toString());
+ syncResult.stats.numParseExceptions++;
+ return;
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error updating database: " + e.toString());
+ syncResult.databaseError = true;
+ return;
+ } catch (OperationApplicationException e) {
+ Log.e(TAG, "Error updating database: " + e.toString());
+ syncResult.databaseError = true;
+ return;
+ }
+ Log.i(TAG, "Network synchronization complete");
+ }
+
+ /**
+ * Read XML from an input stream, storing it into the content provider.
+ *
+ * This is where incoming data is persisted, committing the results of a sync. In order to
+ * minimize (expensive) disk operations, we compare incoming data with what's already in our
+ * database, and compute a merge. Only changes (insert/update/delete) will result in a database
+ * write.
+ *
+ * As an additional optimization, we use a batch operation to perform all database writes at
+ * once.
+ *
+ * Merge strategy:
+ * 1. Get cursor to all items in feed This service is invoked in response to Intents with action android.content.SyncAdapter, and
+ * returns a Binder connection to SyncAdapter.
+ *
+ * For performance, only one sync adapter will be initialized within this application's context.
+ *
+ * Note: The SyncService itself is not notified when a new sync occurs. It's role is to
+ * manage the lifecycle of our {@link SyncAdapter} and provide a handle to said SyncAdapter to the
+ * OS on request.
+ */
+public class SyncService extends Service {
+ private static final String TAG = "SyncService";
+
+ private static final Object sSyncAdapterLock = new Object();
+ private static SyncAdapter sSyncAdapter = null;
+
+ /**
+ * Thread-safe constructor, creates static {@link SyncAdapter} instance.
+ */
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.i(TAG, "Service created");
+ synchronized (sSyncAdapterLock) {
+ if (sSyncAdapter == null) {
+ sSyncAdapter = new SyncAdapter(getApplicationContext(), true);
+ }
+ }
+ }
+
+ @Override
+ /**
+ * Logging-only destructor.
+ */
+ public void onDestroy() {
+ super.onDestroy();
+ Log.i(TAG, "Service destroyed");
+ }
+
+ /**
+ * Return Binder handle for IPC communication with {@link SyncAdapter}.
+ *
+ * New sync requests will be sent directly to the SyncAdapter using this channel.
+ *
+ * @param intent Calling intent
+ * @return Binder handle for {@link SyncAdapter}
+ */
+ @Override
+ public IBinder onBind(Intent intent) {
+ return sSyncAdapter.getSyncAdapterBinder();
+ }
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncUtils.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncUtils.java
new file mode 100644
index 000000000..b327c7287
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/SyncUtils.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2013 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.example.android.basicsyncadapter;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.annotation.TargetApi;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Build;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+
+import com.example.android.common.accounts.GenericAccountService;
+import com.example.android.basicsyncadapter.provider.FeedContract;
+
+/**
+ * Static helper methods for working with the sync framework.
+ */
+public class SyncUtils {
+ private static final long SYNC_FREQUENCY = 60 * 60; // 1 hour (in seconds)
+ private static final String CONTENT_AUTHORITY = FeedContract.CONTENT_AUTHORITY;
+ private static final String PREF_SETUP_COMPLETE = "setup_complete";
+ // Value below must match the account type specified in res/xml/syncadapter.xml
+ public static final String ACCOUNT_TYPE = "com.example.android.basicsyncadapter.account";
+
+ /**
+ * Create an entry for this application in the system account list, if it isn't already there.
+ *
+ * @param context Context
+ */
+ @TargetApi(Build.VERSION_CODES.FROYO)
+ public static void CreateSyncAccount(Context context) {
+ boolean newAccount = false;
+ boolean setupComplete = PreferenceManager
+ .getDefaultSharedPreferences(context).getBoolean(PREF_SETUP_COMPLETE, false);
+
+ // Create account, if it's missing. (Either first run, or user has deleted account.)
+ Account account = GenericAccountService.GetAccount(ACCOUNT_TYPE);
+ AccountManager accountManager =
+ (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
+ if (accountManager.addAccountExplicitly(account, null, null)) {
+ // Inform the system that this account supports sync
+ ContentResolver.setIsSyncable(account, CONTENT_AUTHORITY, 1);
+ // Inform the system that this account is eligible for auto sync when the network is up
+ ContentResolver.setSyncAutomatically(account, CONTENT_AUTHORITY, true);
+ // Recommend a schedule for automatic synchronization. The system may modify this based
+ // on other scheduled syncs and network utilization.
+ ContentResolver.addPeriodicSync(
+ account, CONTENT_AUTHORITY, new Bundle(),SYNC_FREQUENCY);
+ newAccount = true;
+ }
+
+ // Schedule an initial sync if we detect problems with either our account or our local
+ // data has been deleted. (Note that it's possible to clear app data WITHOUT affecting
+ // the account list, so wee need to check both.)
+ if (newAccount || !setupComplete) {
+ TriggerRefresh();
+ PreferenceManager.getDefaultSharedPreferences(context).edit()
+ .putBoolean(PREF_SETUP_COMPLETE, true).commit();
+ }
+ }
+
+ /**
+ * Helper method to trigger an immediate sync ("refresh").
+ *
+ * This should only be used when we need to preempt the normal sync schedule. Typically, this
+ * means the user has pressed the "refresh" button.
+ *
+ * Note that SYNC_EXTRAS_MANUAL will cause an immediate sync, without any optimization to
+ * preserve battery life. If you know new data is available (perhaps via a GCM notification),
+ * but the user is not actively waiting for that data, you should omit this flag; this will give
+ * the OS additional freedom in scheduling your sync request.
+ */
+ public static void TriggerRefresh() {
+ Bundle b = new Bundle();
+ // Disable sync backoff and ignore sync preferences. In other words...perform sync NOW!
+ b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+ b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
+ ContentResolver.requestSync(
+ GenericAccountService.GetAccount(ACCOUNT_TYPE), // Sync account
+ FeedContract.CONTENT_AUTHORITY, // Content authority
+ b); // Extras
+ }
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/net/FeedParser.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/net/FeedParser.java
new file mode 100644
index 000000000..a778390ab
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/net/FeedParser.java
@@ -0,0 +1,278 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * 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.example.android.basicsyncadapter.net;
+
+import android.text.format.Time;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class parses generic Atom feeds.
+ *
+ * Given an InputStream representation of a feed, it returns a List of entries,
+ * where each list element represents a single entry (post) in the XML feed.
+ *
+ * An example of an Atom feed can be found at:
+ * http://en.wikipedia.org/w/index.php?title=Atom_(standard)&oldid=560239173#Example_of_an_Atom_1.0_feed
+ */
+public class FeedParser {
+
+ // Constants indicting XML element names that we're interested in
+ private static final int TAG_ID = 1;
+ private static final int TAG_TITLE = 2;
+ private static final int TAG_PUBLISHED = 3;
+ private static final int TAG_LINK = 4;
+
+ // We don't use XML namespaces
+ private static final String ns = null;
+
+ /** Parse an Atom feed, returning a collection of Entry objects.
+ *
+ * @param in Atom feed, as a stream.
+ * @return List of {@link com.example.android.basicsyncadapter.net.FeedParser.Entry} objects.
+ * @throws org.xmlpull.v1.XmlPullParserException on error parsing feed.
+ * @throws java.io.IOException on I/O error.
+ */
+ public List You probably want to call readTag().
+ *
+ * @param parser Current parser object
+ * @param tag XML element tag name to parse
+ * @return Body of the specified tag
+ * @throws java.io.IOException
+ * @throws org.xmlpull.v1.XmlPullParserException
+ */
+ private String readBasicTag(XmlPullParser parser, String tag)
+ throws IOException, XmlPullParserException {
+ parser.require(XmlPullParser.START_TAG, ns, tag);
+ String result = readText(parser);
+ parser.require(XmlPullParser.END_TAG, ns, tag);
+ return result;
+ }
+
+ /**
+ * Processes link tags in the feed.
+ */
+ private String readAlternateLink(XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ String link = null;
+ parser.require(XmlPullParser.START_TAG, ns, "link");
+ String tag = parser.getName();
+ String relType = parser.getAttributeValue(null, "rel");
+ if (relType.equals("alternate")) {
+ link = parser.getAttributeValue(null, "href");
+ }
+ while (true) {
+ if (parser.nextTag() == XmlPullParser.END_TAG) break;
+ // Intentionally break; consumes any remaining sub-tags.
+ }
+ return link;
+ }
+
+ /**
+ * For the tags title and summary, extracts their text values.
+ */
+ private String readText(XmlPullParser parser) throws IOException, XmlPullParserException {
+ String result = null;
+ if (parser.next() == XmlPullParser.TEXT) {
+ result = parser.getText();
+ parser.nextTag();
+ }
+ return result;
+ }
+
+ /**
+ * Skips tags the parser isn't interested in. Uses depth to handle nested tags. i.e.,
+ * if the next tag after a START_TAG isn't a matching END_TAG, it keeps going until it
+ * finds the matching END_TAG (as indicated by the value of "depth" being 0).
+ */
+ private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+ if (parser.getEventType() != XmlPullParser.START_TAG) {
+ throw new IllegalStateException();
+ }
+ int depth = 1;
+ while (depth != 0) {
+ switch (parser.next()) {
+ case XmlPullParser.END_TAG:
+ depth--;
+ break;
+ case XmlPullParser.START_TAG:
+ depth++;
+ break;
+ }
+ }
+ }
+
+ /**
+ * This class represents a single entry (post) in the XML feed.
+ *
+ * It includes the data members "title," "link," and "summary."
+ */
+ public static class Entry {
+ public final String id;
+ public final String title;
+ public final String link;
+ public final long published;
+
+ Entry(String id, String title, String link, long published) {
+ this.id = id;
+ this.title = title;
+ this.link = link;
+ this.published = published;
+ }
+ }
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedContract.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedContract.java
new file mode 100644
index 000000000..e29ec4823
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedContract.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * 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.example.android.basicsyncadapter.provider;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.provider.BaseColumns;
+
+/**
+ * Field and table name constants for
+ * {@link com.example.android.basicsyncadapter.provider.FeedProvider}.
+ */
+public class FeedContract {
+ private FeedContract() {
+ }
+
+ /**
+ * Content provider authority.
+ */
+ public static final String CONTENT_AUTHORITY = "com.example.android.basicsyncadapter";
+
+ /**
+ * Base URI. (content://com.example.android.basicsyncadapter)
+ */
+ public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
+
+ /**
+ * Path component for "entry"-type resources..
+ */
+ private static final String PATH_ENTRIES = "entries";
+
+ /**
+ * Columns supported by "entries" records.
+ */
+ public static class Entry implements BaseColumns {
+ /**
+ * MIME type for lists of entries.
+ */
+ public static final String CONTENT_TYPE =
+ ContentResolver.CURSOR_DIR_BASE_TYPE + "/vnd.basicsyncadapter.entries";
+ /**
+ * MIME type for individual entries.
+ */
+ public static final String CONTENT_ITEM_TYPE =
+ ContentResolver.CURSOR_ITEM_BASE_TYPE + "/vnd.basicsyncadapter.entry";
+
+ /**
+ * Fully qualified URI for "entry" resources.
+ */
+ public static final Uri CONTENT_URI =
+ BASE_CONTENT_URI.buildUpon().appendPath(PATH_ENTRIES).build();
+
+ /**
+ * Table name where records are stored for "entry" resources.
+ */
+ public static final String TABLE_NAME = "entry";
+ /**
+ * Atom ID. (Note: Not to be confused with the database primary key, which is _ID.
+ */
+ public static final String COLUMN_NAME_ENTRY_ID = "entry_id";
+ /**
+ * Article title
+ */
+ public static final String COLUMN_NAME_TITLE = "title";
+ /**
+ * Article hyperlink. Corresponds to the rel="alternate" link in the
+ * Atom spec.
+ */
+ public static final String COLUMN_NAME_LINK = "link";
+ /**
+ * Date article was published.
+ */
+ public static final String COLUMN_NAME_PUBLISHED = "published";
+ }
+}
\ No newline at end of file
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedProvider.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedProvider.java
new file mode 100644
index 000000000..80bf1d3d5
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.basicsyncadapter/provider/FeedProvider.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * 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.example.android.basicsyncadapter.provider;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.net.Uri;
+
+import com.example.android.common.db.SelectionBuilder;
+
+public class FeedProvider extends ContentProvider {
+ FeedDatabase mDatabaseHelper;
+
+ /**
+ * Content authority for this provider.
+ */
+ private static final String AUTHORITY = FeedContract.CONTENT_AUTHORITY;
+
+ // The constants below represent individual URI routes, as IDs. Every URI pattern recognized by
+ // this ContentProvider is defined using sUriMatcher.addURI(), and associated with one of these
+ // IDs.
+ //
+ // When a incoming URI is run through sUriMatcher, it will be tested against the defined
+ // URI patterns, and the corresponding route ID will be returned.
+ /**
+ * URI ID for route: /entries
+ */
+ public static final int ROUTE_ENTRIES = 1;
+
+ /**
+ * URI ID for route: /entries/{ID}
+ */
+ public static final int ROUTE_ENTRIES_ID = 2;
+
+ /**
+ * UriMatcher, used to decode incoming URIs.
+ */
+ private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+ static {
+ sUriMatcher.addURI(AUTHORITY, "entries", ROUTE_ENTRIES);
+ sUriMatcher.addURI(AUTHORITY, "entries/*", ROUTE_ENTRIES_ID);
+ }
+
+ @Override
+ public boolean onCreate() {
+ mDatabaseHelper = new FeedDatabase(getContext());
+ return true;
+ }
+
+ /**
+ * Determine the mime type for entries returned by a given URI.
+ */
+ @Override
+ public String getType(Uri uri) {
+ final int match = sUriMatcher.match(uri);
+ switch (match) {
+ case ROUTE_ENTRIES:
+ return FeedContract.Entry.CONTENT_TYPE;
+ case ROUTE_ENTRIES_ID:
+ return FeedContract.Entry.CONTENT_ITEM_TYPE;
+ default:
+ throw new UnsupportedOperationException("Unknown uri: " + uri);
+ }
+ }
+
+ /**
+ * Perform a database query by URI.
+ *
+ * Currently supports returning all entries (/entries) and individual entries by ID
+ * (/entries/{ID}).
+ */
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
+ SelectionBuilder builder = new SelectionBuilder();
+ int uriMatch = sUriMatcher.match(uri);
+ switch (uriMatch) {
+ case ROUTE_ENTRIES_ID:
+ // Return a single entry, by ID.
+ String id = uri.getLastPathSegment();
+ builder.where(FeedContract.Entry._ID + "=?", id);
+ case ROUTE_ENTRIES:
+ // Return all known entries.
+ builder.table(FeedContract.Entry.TABLE_NAME)
+ .where(selection, selectionArgs);
+ Cursor c = builder.query(db, projection, sortOrder);
+ // Note: Notification URI must be manually set here for loaders to correctly
+ // register ContentObservers.
+ Context ctx = getContext();
+ assert ctx != null;
+ c.setNotificationUri(ctx.getContentResolver(), uri);
+ return c;
+ default:
+ throw new UnsupportedOperationException("Unknown uri: " + uri);
+ }
+ }
+
+ /**
+ * Insert a new entry into the database.
+ */
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
+ assert db != null;
+ final int match = sUriMatcher.match(uri);
+ Uri result;
+ switch (match) {
+ case ROUTE_ENTRIES:
+ long id = db.insertOrThrow(FeedContract.Entry.TABLE_NAME, null, values);
+ result = Uri.parse(FeedContract.Entry.CONTENT_URI + "/" + id);
+ break;
+ case ROUTE_ENTRIES_ID:
+ throw new UnsupportedOperationException("Insert not supported on URI: " + uri);
+ default:
+ throw new UnsupportedOperationException("Unknown uri: " + uri);
+ }
+ // Send broadcast to registered ContentObservers, to refresh UI.
+ Context ctx = getContext();
+ assert ctx != null;
+ ctx.getContentResolver().notifyChange(uri, null, false);
+ return result;
+ }
+
+ /**
+ * Delete an entry by database by URI.
+ */
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ SelectionBuilder builder = new SelectionBuilder();
+ final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
+ final int match = sUriMatcher.match(uri);
+ int count;
+ switch (match) {
+ case ROUTE_ENTRIES:
+ count = builder.table(FeedContract.Entry.TABLE_NAME)
+ .where(selection, selectionArgs)
+ .delete(db);
+ break;
+ case ROUTE_ENTRIES_ID:
+ String id = uri.getLastPathSegment();
+ count = builder.table(FeedContract.Entry.TABLE_NAME)
+ .where(FeedContract.Entry._ID + "=?", id)
+ .where(selection, selectionArgs)
+ .delete(db);
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown uri: " + uri);
+ }
+ // Send broadcast to registered ContentObservers, to refresh UI.
+ Context ctx = getContext();
+ assert ctx != null;
+ ctx.getContentResolver().notifyChange(uri, null, false);
+ return count;
+ }
+
+ /**
+ * Update an etry in the database by URI.
+ */
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ SelectionBuilder builder = new SelectionBuilder();
+ final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
+ final int match = sUriMatcher.match(uri);
+ int count;
+ switch (match) {
+ case ROUTE_ENTRIES:
+ count = builder.table(FeedContract.Entry.TABLE_NAME)
+ .where(selection, selectionArgs)
+ .update(db, values);
+ break;
+ case ROUTE_ENTRIES_ID:
+ String id = uri.getLastPathSegment();
+ count = builder.table(FeedContract.Entry.TABLE_NAME)
+ .where(FeedContract.Entry._ID + "=?", id)
+ .where(selection, selectionArgs)
+ .update(db, values);
+ break;
+ default:
+ throw new UnsupportedOperationException("Unknown uri: " + uri);
+ }
+ Context ctx = getContext();
+ assert ctx != null;
+ ctx.getContentResolver().notifyChange(uri, null, false);
+ return count;
+ }
+
+ /**
+ * SQLite backend for @{link FeedProvider}.
+ *
+ * Provides access to an disk-backed, SQLite datastore which is utilized by FeedProvider. This
+ * database should never be accessed by other parts of the application directly.
+ */
+ static class FeedDatabase extends SQLiteOpenHelper {
+ /** Schema version. */
+ public static final int DATABASE_VERSION = 1;
+ /** Filename for SQLite file. */
+ public static final String DATABASE_NAME = "feed.db";
+
+ private static final String TYPE_TEXT = " TEXT";
+ private static final String TYPE_INTEGER = " INTEGER";
+ private static final String COMMA_SEP = ",";
+ /** SQL statement to create "entry" table. */
+ private static final String SQL_CREATE_ENTRIES =
+ "CREATE TABLE " + FeedContract.Entry.TABLE_NAME + " (" +
+ FeedContract.Entry._ID + " INTEGER PRIMARY KEY," +
+ FeedContract.Entry.COLUMN_NAME_ENTRY_ID + TYPE_TEXT + COMMA_SEP +
+ FeedContract.Entry.COLUMN_NAME_TITLE + TYPE_TEXT + COMMA_SEP +
+ FeedContract.Entry.COLUMN_NAME_LINK + TYPE_TEXT + COMMA_SEP +
+ FeedContract.Entry.COLUMN_NAME_PUBLISHED + TYPE_INTEGER + ")";
+
+ /** SQL statement to drop "entry" table. */
+ private static final String SQL_DELETE_ENTRIES =
+ "DROP TABLE IF EXISTS " + FeedContract.Entry.TABLE_NAME;
+
+ public FeedDatabase(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(SQL_CREATE_ENTRIES);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // This database is only a cache for online data, so its upgrade policy is
+ // to simply to discard the data and start over
+ db.execSQL(SQL_DELETE_ENTRIES);
+ onCreate(db);
+ }
+ }
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.common/accounts/GenericAccountService.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/accounts/GenericAccountService.java
new file mode 100644
index 000000000..0cd499a88
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/accounts/GenericAccountService.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * 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.example.android.common.accounts;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.NetworkErrorException;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+
+public class GenericAccountService extends Service {
+ private static final String TAG = "GenericAccountService";
+ public static final String ACCOUNT_NAME = "Account";
+ private Authenticator mAuthenticator;
+
+ /**
+ * Obtain a handle to the {@link android.accounts.Account} used for sync in this application.
+ *
+ * It is important that the accountType specified here matches the value in your sync adapter
+ * configuration XML file for android.accounts.AccountAuthenticator (often saved in
+ * res/xml/syncadapter.xml). If this is not set correctly, you'll receive an error indicating
+ * that "caller uid XXXXX is different than the authenticator's uid".
+ *
+ * @param accountType AccountType defined in the configuration XML file for
+ * android.accounts.AccountAuthenticator (e.g. res/xml/syncadapter.xml).
+ * @return Handle to application's account (not guaranteed to resolve unless CreateSyncAccount()
+ * has been called)
+ */
+ public static Account GetAccount(String accountType) {
+ // Note: Normally the account name is set to the user's identity (username or email
+ // address). However, since we aren't actually using any user accounts, it makes more sense
+ // to use a generic string in this case.
+ //
+ // This string should *not* be localized. If the user switches locale, we would not be
+ // able to locate the old account, and may erroneously register multiple accounts.
+ final String accountName = ACCOUNT_NAME;
+ return new Account(accountName, accountType);
+ }
+
+ @Override
+ public void onCreate() {
+ Log.i(TAG, "Service created");
+ mAuthenticator = new Authenticator(this);
+ }
+
+ @Override
+ public void onDestroy() {
+ Log.i(TAG, "Service destroyed");
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mAuthenticator.getIBinder();
+ }
+
+ public class Authenticator extends AbstractAccountAuthenticator {
+ public Authenticator(Context context) {
+ super(context);
+ }
+
+ @Override
+ public Bundle editProperties(AccountAuthenticatorResponse accountAuthenticatorResponse,
+ String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Bundle addAccount(AccountAuthenticatorResponse accountAuthenticatorResponse,
+ String s, String s2, String[] strings, Bundle bundle)
+ throws NetworkErrorException {
+ return null;
+ }
+
+ @Override
+ public Bundle confirmCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse,
+ Account account, Bundle bundle)
+ throws NetworkErrorException {
+ return null;
+ }
+
+ @Override
+ public Bundle getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse,
+ Account account, String s, Bundle bundle)
+ throws NetworkErrorException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getAuthTokenLabel(String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Bundle updateCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse,
+ Account account, String s, Bundle bundle)
+ throws NetworkErrorException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Bundle hasFeatures(AccountAuthenticatorResponse accountAuthenticatorResponse,
+ Account account, String[] strings)
+ throws NetworkErrorException {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+}
+
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.common/db/SelectionBuilder.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/db/SelectionBuilder.java
new file mode 100644
index 000000000..a1964c5f3
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/db/SelectionBuilder.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * 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.
+ */
+
+/*
+ * Modifications:
+ * -Imported from AOSP frameworks/base/core/java/com/android/internal/content
+ * -Changed package name
+ */
+
+package com.example.android.common.db;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Helper for building selection clauses for {@link SQLiteDatabase}.
+ *
+ * This class provides a convenient frontend for working with SQL. Instead of composing statements
+ * manually using string concatenation, method calls are used to construct the statement one
+ * clause at a time. These methods can be chained together.
+ *
+ * If multiple where() statements are provided, they're combined using {@code AND}.
+ *
+ * Example:
+ *
+ * In this example, the table name and filters ({@code WHERE} clauses) are both explicitly
+ * specified via method call. SelectionBuilder takes care of issuing a "query" command to the
+ * database, and returns the resulting {@link Cursor} object.
+ *
+ * Inner {@code JOIN}s can be accomplished using the mapToTable() function. The map() function
+ * can be used to create new columns based on arbitrary (SQL-based) criteria. In advanced usage,
+ * entire subqueries can be passed into the map() function.
+ *
+ * Advanced example:
+ *
+ * In this example, we have two different types of {@code JOIN}s: a left outer join using a
+ * modified table name (since this class doesn't directly support these), and an inner join using
+ * the mapToTable() function. The map() function is used to insert a count based on specific
+ * criteria, executed as a sub-query.
+ *
+ * This class is not thread safe.
+ */
+public class SelectionBuilder {
+ private static final String TAG = "basicsyncadapter";
+
+ private String mTable = null;
+ private Map Calling this method is more efficient than creating a new SelectionBuilder object.
+ *
+ * @return Fluent interface
+ */
+ public SelectionBuilder reset() {
+ mTable = null;
+ mSelection.setLength(0);
+ mSelectionArgs.clear();
+ return this;
+ }
+
+ /**
+ * Append the given selection clause to the internal state. Each clause is
+ * surrounded with parenthesis and combined using {@code AND}.
+ *
+ * In the most basic usage, simply provide a selection in SQL {@code WHERE} statement format.
+ *
+ * Example:
+ *
+ * User input should never be directly supplied as as part of the selection statement.
+ * Instead, use positional parameters in your selection statement, then pass the user input
+ * in via the selectionArgs parameter. This prevents SQL escape characters in user input from
+ * causing unwanted side effects. (Failure to follow this convention may have security
+ * implications.)
+ *
+ * Positional parameters are specified using the '?' character.
+ *
+ * Example:
+ * This method may only be called once. If multiple tables are required, concatenate them
+ * in SQL-format (typically comma-separated).
+ *
+ * If you need to do advanced {@code JOIN}s, they can also be specified here.
+ *
+ * See also: mapToTable()
+ *
+ * @param table Table name
+ * @return Fluent interface
+ */
+ public SelectionBuilder table(String table) {
+ mTable = table;
+ return this;
+ }
+
+ /**
+ * Verify that a table name has been supplied using table().
+ *
+ * @throws IllegalStateException if table not set
+ */
+ private void assertTable() {
+ if (mTable == null) {
+ throw new IllegalStateException("Table not specified");
+ }
+ }
+
+ /**
+ * Perform an inner join.
+ *
+ * Map columns from a secondary table onto the current result set. References to the column
+ * specified in {@code column} will be replaced with {@code table.column} in the SQL {@code
+ * SELECT} clause.
+ *
+ * @param column Column name to join on. Must be the same in both tables.
+ * @param table Secondary table to join.
+ * @return Fluent interface
+ */
+ public SelectionBuilder mapToTable(String column, String table) {
+ mProjectionMap.put(column, table + "." + column);
+ return this;
+ }
+
+ /**
+ * Create a new column based on custom criteria (such as aggregate functions).
+ *
+ * This adds a new column to the result set, based upon custom criteria in SQL format. This
+ * is equivalent to the SQL statement: {@code SELECT toClause AS fromColumn}
+ *
+ * This method is useful for executing SQL sub-queries.
+ *
+ * @param fromColumn Name of column for mapping
+ * @param toClause SQL string representing data to be mapped
+ * @return Fluent interface
+ */
+ public SelectionBuilder map(String fromColumn, String toClause) {
+ mProjectionMap.put(fromColumn, toClause + " AS " + fromColumn);
+ return this;
+ }
+
+ /**
+ * Return selection string based on current internal state.
+ *
+ * @return Current selection as a SQL statement
+ * @see #getSelectionArgs()
+ */
+ public String getSelection() {
+ return mSelection.toString();
+
+ }
+
+ /**
+ * Return selection arguments based on current internal state.
+ *
+ * @see #getSelection()
+ */
+ public String[] getSelectionArgs() {
+ return mSelectionArgs.toArray(new String[mSelectionArgs.size()]);
+ }
+
+ /**
+ * Process user-supplied projection (column list).
+ *
+ * In cases where a column is mapped to another data source (either another table, or an
+ * SQL sub-query), the column name will be replaced with a more specific, SQL-compatible
+ * representation.
+ *
+ * Assumes that incoming columns are non-null.
+ *
+ * See also: map(), mapToTable()
+ *
+ * @param columns User supplied projection (column list).
+ */
+ private void mapColumns(String[] columns) {
+ for (int i = 0; i < columns.length; i++) {
+ final String target = mProjectionMap.get(columns[i]);
+ if (target != null) {
+ columns[i] = target;
+ }
+ }
+ }
+
+ /**
+ * Return a description of this builder's state. Does NOT output SQL.
+ *
+ * @return Human-readable internal state
+ */
+ @Override
+ public String toString() {
+ return "SelectionBuilder[table=" + mTable + ", selection=" + getSelection()
+ + ", selectionArgs=" + Arrays.toString(getSelectionArgs()) + "]";
+ }
+
+ /**
+ * Execute query (SQL {@code SELECT}) against specified database.
+ *
+ * Using a null projection (column list) is not supported.
+ *
+ * @param db Database to query.
+ * @param columns Database projection (column list) to return, must be non-NULL.
+ * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause (excluding the
+ * ORDER BY itself). Passing null will use the default sort order, which may be
+ * unordered.
+ * @return A {@link Cursor} object, which is positioned before the first entry. Note that
+ * {@link Cursor}s are not synchronized, see the documentation for more details.
+ */
+ public Cursor query(SQLiteDatabase db, String[] columns, String orderBy) {
+ return query(db, columns, null, null, orderBy, null);
+ }
+
+ /**
+ * Execute query ({@code SELECT}) against database.
+ *
+ * Using a null projection (column list) is not supported.
+ *
+ * @param db Database to query.
+ * @param columns Database projection (column list) to return, must be non-null.
+ * @param groupBy A filter declaring how to group rows, formatted as an SQL GROUP BY clause
+ * (excluding the GROUP BY itself). Passing null will cause the rows to not be
+ * grouped.
+ * @param having A filter declare which row groups to include in the cursor, if row grouping is
+ * being used, formatted as an SQL HAVING clause (excluding the HAVING itself).
+ * Passing null will cause all row groups to be included, and is required when
+ * row grouping is not being used.
+ * @param orderBy How to order the rows, formatted as an SQL ORDER BY clause (excluding the
+ * ORDER BY itself). Passing null will use the default sort order, which may be
+ * unordered.
+ * @param limit Limits the number of rows returned by the query, formatted as LIMIT clause.
+ * Passing null denotes no LIMIT clause.
+ * @return A {@link Cursor} object, which is positioned before the first entry. Note that
+ * {@link Cursor}s are not synchronized, see the documentation for more details.
+ */
+ public Cursor query(SQLiteDatabase db, String[] columns, String groupBy,
+ String having, String orderBy, String limit) {
+ assertTable();
+ if (columns != null) mapColumns(columns);
+ Log.v(TAG, "query(columns=" + Arrays.toString(columns) + ") " + this);
+ return db.query(mTable, columns, getSelection(), getSelectionArgs(), groupBy, having,
+ orderBy, limit);
+ }
+
+ /**
+ * Execute an {@code UPDATE} against database.
+ *
+ * @param db Database to query.
+ * @param values A map from column names to new column values. null is a valid value that will
+ * be translated to NULL
+ * @return The number of rows affected.
+ */
+ public int update(SQLiteDatabase db, ContentValues values) {
+ assertTable();
+ Log.v(TAG, "update() " + this);
+ return db.update(mTable, values, getSelection(), getSelectionArgs());
+ }
+
+ /**
+ * Execute {@code DELETE} against database.
+ *
+ * @param db Database to query.
+ * @return The number of rows affected.
+ */
+ public int delete(SQLiteDatabase db) {
+ assertTable();
+ Log.v(TAG, "delete() " + this);
+ return db.delete(mTable, getSelection(), getSelectionArgs());
+ }
+}
diff --git a/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/Log.java b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/Log.java
new file mode 100644
index 000000000..17503c568
--- /dev/null
+++ b/samples/browseable/BasicSyncAdapter/src/com.example.android.common/logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.
+
+ This sample demonstrates how to use the Bluetooth LE Generic Attribute Profile (GATT)
+ to transmit arbitrary data between devices.
+
+
+
+ This sample demonstrates the use of borderless buttons, bottom button bars
+ (OK and Cancel) and dividers to establish visual structure.
+
+
+ * See
+ * borderless buttons at the Android Design guide for a discussion of this visual style.
+ */
+public class MainActivity extends ListActivity {
+ private static final Uri DOCS_URI = Uri.parse(
+ "http://developer.android.com/design/building-blocks/buttons.html#borderless");
+
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.sample_main);
+
+ setListAdapter(mListAdapter);
+
+ findViewById(R.id.cancel_button).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ finish();
+ }
+ });
+
+ findViewById(R.id.ok_button).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ finish();
+ }
+ });
+ }
+
+ private BaseAdapter mListAdapter = new BaseAdapter() {
+ @Override
+ public int getCount() {
+ return 10;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position + 1;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup container) {
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(R.layout.list_item, container, false);
+ }
+
+ // Because the list item contains multiple touch targets, you should not override
+ // onListItemClick. Instead, set a click listener for each target individually.
+
+ convertView.findViewById(R.id.primary_target).setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Toast.makeText(MainActivity.this,
+ R.string.touched_primary_message,
+ Toast.LENGTH_SHORT).show();
+ }
+ });
+
+ convertView.findViewById(R.id.secondary_action).setOnClickListener(
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ Toast.makeText(MainActivity.this,
+ R.string.touched_secondary_message,
+ Toast.LENGTH_SHORT).show();
+ }
+ });
+ return convertView;
+ }
+ };
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ getMenuInflater().inflate(R.menu.main, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.docs_link:
+ try {
+ startActivity(new Intent(Intent.ACTION_VIEW, DOCS_URI));
+ } catch (ActivityNotFoundException ignored) {
+ }
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/Log.java b/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/Log.java
new file mode 100644
index 000000000..17503c568
--- /dev/null
+++ b/samples/browseable/BorderlessButtons/src/com.example.android.common.logger/Log.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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.example.android.common.logger;
+
+/**
+ * Helper class for a list (or tree) of LoggerNodes.
+ *
+ * When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.
+
+ This sample demonstrates how to create custom checkable layouts, for use with ListView\'s choiceMode
+ attribute.
+
+ When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.
+ * This can be used as the root view for a custom list item layout for
+ * {@link android.widget.AbsListView} elements with a
+ * {@link android.widget.AbsListView#setChoiceMode(int) choiceMode} set.
+ */
+public class CheckableLinearLayout extends LinearLayout implements Checkable {
+ private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};
+
+ private boolean mChecked = false;
+
+ public CheckableLinearLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public boolean isChecked() {
+ return mChecked;
+ }
+
+ public void setChecked(boolean b) {
+ if (b != mChecked) {
+ mChecked = b;
+ refreshDrawableState();
+ }
+ }
+
+ public void toggle() {
+ setChecked(!mChecked);
+ }
+
+ @Override
+ public int[] onCreateDrawableState(int extraSpace) {
+ final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+ if (isChecked()) {
+ mergeDrawableStates(drawableState, CHECKED_STATE_SET);
+ }
+ return drawableState;
+ }
+}
diff --git a/samples/browseable/CustomChoiceList/src/com.example.android.customchoicelist/Cheeses.java b/samples/browseable/CustomChoiceList/src/com.example.android.customchoicelist/Cheeses.java
new file mode 100644
index 000000000..871ae2929
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/src/com.example.android.customchoicelist/Cheeses.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * 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.example.android.customchoicelist;
+
+/**
+ * Dummy data.
+ */
+public class Cheeses {
+ public static final String[] CHEESES = {
+ "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
+ "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
+ "Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese",
+ "Ami du Chambertin", "Anejo Enchilado", "Anneau du Vic-Bilh", "Anthoriro", "Appenzell",
+ "Aragon", "Ardi Gasna", "Ardrahan", "Armenian String", "Aromes au Gene de Marc",
+ "Asadero", "Asiago", "Aubisque Pyrenees", "Autun", "Avaxtskyr", "Baby Swiss",
+ "Babybel", "Baguette Laonnaise", "Bakers", "Baladi", "Balaton", "Bandal", "Banon",
+ "Barry's Bay Cheddar", "Basing", "Basket Cheese", "Bath Cheese", "Bavarian Bergkase",
+ "Baylough", "Beaufort", "Beauvoorde", "Beenleigh Blue", "Beer Cheese", "Bel Paese",
+ "Bergader", "Bergere Bleue", "Berkswell", "Beyaz Peynir", "Bierkase", "Bishop Kennedy",
+ "Blarney", "Bleu d'Auvergne", "Bleu de Gex", "Bleu de Laqueuille",
+ "Bleu de Septmoncel", "Bleu Des Causses", "Blue", "Blue Castello", "Blue Rathgore",
+ "Blue Vein (Australian)", "Blue Vein Cheeses", "Bocconcini", "Bocconcini (Australian)",
+ "Boeren Leidenkaas", "Bonchester", "Bosworth", "Bougon", "Boule Du Roves",
+ "Boulette d'Avesnes", "Boursault", "Boursin", "Bouyssou", "Bra", "Braudostur",
+ "Breakfast Cheese", "Brebis du Lavort", "Brebis du Lochois", "Brebis du Puyfaucon",
+ "Bresse Bleu", "Brick", "Brie", "Brie de Meaux", "Brie de Melun", "Brillat-Savarin",
+ "Brin", "Brin d' Amour", "Brin d'Amour", "Brinza (Burduf Brinza)",
+ "Briquette de Brebis", "Briquette du Forez", "Broccio", "Broccio Demi-Affine",
+ "Brousse du Rove", "Bruder Basil", "Brusselae Kaas (Fromage de Bruxelles)", "Bryndza",
+ "Buchette d'Anjou", "Buffalo", "Burgos", "Butte", "Butterkase", "Button (Innes)",
+ "Buxton Blue", "Cabecou", "Caboc", "Cabrales", "Cachaille", "Caciocavallo", "Caciotta",
+ "Caerphilly", "Cairnsmore", "Calenzana", "Cambazola", "Camembert de Normandie",
+ "Canadian Cheddar", "Canestrato", "Cantal", "Caprice des Dieux", "Capricorn Goat",
+ "Capriole Banon", "Carre de l'Est", "Casciotta di Urbino", "Cashel Blue", "Castellano",
+ "Castelleno", "Castelmagno", "Castelo Branco", "Castigliano", "Cathelain",
+ "Celtic Promise", "Cendre d'Olivet", "Cerney", "Chabichou", "Chabichou du Poitou",
+ "Chabis de Gatine", "Chaource", "Charolais", "Chaumes", "Cheddar",
+ "Cheddar Clothbound", "Cheshire", "Chevres", "Chevrotin des Aravis", "Chontaleno",
+ "Civray", "Coeur de Camembert au Calvados", "Coeur de Chevre", "Colby", "Cold Pack",
+ "Comte", "Coolea", "Cooleney", "Coquetdale", "Corleggy", "Cornish Pepper",
+ "Cotherstone", "Cotija", "Cottage Cheese", "Cottage Cheese (Australian)",
+ "Cougar Gold", "Coulommiers", "Coverdale", "Crayeux de Roncq", "Cream Cheese",
+ "Cream Havarti", "Crema Agria", "Crema Mexicana", "Creme Fraiche", "Crescenza",
+ "Croghan", "Crottin de Chavignol", "Crottin du Chavignol", "Crowdie", "Crowley",
+ "Cuajada", "Curd", "Cure Nantais", "Curworthy", "Cwmtawe Pecorino",
+ "Cypress Grove Chevre", "Danablu (Danish Blue)", "Danbo", "Danish Fontina",
+ "Daralagjazsky", "Dauphin", "Delice des Fiouves", "Denhany Dorset Drum", "Derby",
+ "Dessertnyj Belyj", "Devon Blue", "Devon Garland", "Dolcelatte", "Doolin",
+ "Doppelrhamstufel", "Dorset Blue Vinney", "Double Gloucester", "Double Worcester",
+ "Dreux a la Feuille", "Dry Jack", "Duddleswell", "Dunbarra", "Dunlop", "Dunsyre Blue",
+ "Duroblando", "Durrus", "Dutch Mimolette (Commissiekaas)", "Edam", "Edelpilz",
+ "Emental Grand Cru", "Emlett", "Emmental", "Epoisses de Bourgogne", "Esbareich",
+ "Esrom", "Etorki", "Evansdale Farmhouse Brie", "Evora De L'Alentejo", "Exmoor Blue",
+ "Explorateur", "Feta", "Feta (Australian)", "Figue", "Filetta", "Fin-de-Siecle",
+ "Finlandia Swiss", "Finn", "Fiore Sardo", "Fleur du Maquis", "Flor de Guia",
+ "Flower Marie", "Folded", "Folded cheese with mint", "Fondant de Brebis",
+ "Fontainebleau", "Fontal", "Fontina Val d'Aosta", "Formaggio di capra", "Fougerus",
+ "Four Herb Gouda", "Fourme d' Ambert", "Fourme de Haute Loire", "Fourme de Montbrison",
+ "Fresh Jack", "Fresh Mozzarella", "Fresh Ricotta", "Fresh Truffles", "Fribourgeois",
+ "Friesekaas", "Friesian", "Friesla", "Frinault", "Fromage a Raclette", "Fromage Corse",
+ "Fromage de Montagne de Savoie", "Fromage Frais", "Fruit Cream Cheese",
+ "Frying Cheese", "Fynbo", "Gabriel", "Galette du Paludier", "Galette Lyonnaise",
+ "Galloway Goat's Milk Gems", "Gammelost", "Gaperon a l'Ail", "Garrotxa", "Gastanberra",
+ "Geitost", "Gippsland Blue", "Gjetost", "Gloucester", "Golden Cross", "Gorgonzola",
+ "Gornyaltajski", "Gospel Green", "Gouda", "Goutu", "Gowrie", "Grabetto", "Graddost",
+ "Grafton Village Cheddar", "Grana", "Grana Padano", "Grand Vatel",
+ "Grataron d' Areches", "Gratte-Paille", "Graviera", "Greuilh", "Greve",
+ "Gris de Lille", "Gruyere", "Gubbeen", "Guerbigny", "Halloumi",
+ "Halloumy (Australian)", "Haloumi-Style Cheese", "Harbourne Blue", "Havarti",
+ "Heidi Gruyere", "Hereford Hop", "Herrgardsost", "Herriot Farmhouse", "Herve",
+ "Hipi Iti", "Hubbardston Blue Cow", "Hushallsost", "Iberico", "Idaho Goatster",
+ "Idiazabal", "Il Boschetto al Tartufo", "Ile d'Yeu", "Isle of Mull", "Jarlsberg",
+ "Jermi Tortes", "Jibneh Arabieh", "Jindi Brie", "Jubilee Blue", "Juustoleipa",
+ "Kadchgall", "Kaseri", "Kashta", "Kefalotyri", "Kenafa", "Kernhem", "Kervella Affine",
+ "Kikorangi", "King Island Cape Wickham Brie", "King River Gold", "Klosterkaese",
+ "Knockalara", "Kugelkase", "L'Aveyronnais", "L'Ecir de l'Aubrac", "La Taupiniere",
+ "La Vache Qui Rit", "Laguiole", "Lairobell", "Lajta", "Lanark Blue", "Lancashire",
+ "Langres", "Lappi", "Laruns", "Lavistown", "Le Brin", "Le Fium Orbo", "Le Lacandou",
+ "Le Roule", "Leafield", "Lebbene", "Leerdammer", "Leicester", "Leyden", "Limburger",
+ "Lincolnshire Poacher", "Lingot Saint Bousquet d'Orb", "Liptauer", "Little Rydings",
+ "Livarot", "Llanboidy", "Llanglofan Farmhouse", "Loch Arthur Farmhouse",
+ "Loddiswell Avondale", "Longhorn", "Lou Palou", "Lou Pevre", "Lyonnais", "Maasdam",
+ "Macconais", "Mahoe Aged Gouda", "Mahon", "Malvern", "Mamirolle", "Manchego",
+ "Manouri", "Manur", "Marble Cheddar", "Marbled Cheeses", "Maredsous", "Margotin",
+ "Maribo", "Maroilles", "Mascares", "Mascarpone", "Mascarpone (Australian)",
+ "Mascarpone Torta", "Matocq", "Maytag Blue", "Meira", "Menallack Farmhouse",
+ "Menonita", "Meredith Blue", "Mesost", "Metton (Cancoillotte)", "Meyer Vintage Gouda",
+ "Mihalic Peynir", "Milleens", "Mimolette", "Mine-Gabhar", "Mini Baby Bells", "Mixte",
+ "Molbo", "Monastery Cheeses", "Mondseer", "Mont D'or Lyonnais", "Montasio",
+ "Monterey Jack", "Monterey Jack Dry", "Morbier", "Morbier Cru de Montagne",
+ "Mothais a la Feuille", "Mozzarella", "Mozzarella (Australian)",
+ "Mozzarella di Bufala", "Mozzarella Fresh, in water", "Mozzarella Rolls", "Munster",
+ "Murol", "Mycella", "Myzithra", "Naboulsi", "Nantais", "Neufchatel",
+ "Neufchatel (Australian)", "Niolo", "Nokkelost", "Northumberland", "Oaxaca",
+ "Olde York", "Olivet au Foin", "Olivet Bleu", "Olivet Cendre",
+ "Orkney Extra Mature Cheddar", "Orla", "Oschtjepka", "Ossau Fermier", "Ossau-Iraty",
+ "Oszczypek", "Oxford Blue", "P'tit Berrichon", "Palet de Babligny", "Paneer", "Panela",
+ "Pannerone", "Pant ys Gawn", "Parmesan (Parmigiano)", "Parmigiano Reggiano",
+ "Pas de l'Escalette", "Passendale", "Pasteurized Processed", "Pate de Fromage",
+ "Patefine Fort", "Pave d'Affinois", "Pave d'Auge", "Pave de Chirac", "Pave du Berry",
+ "Pecorino", "Pecorino in Walnut Leaves", "Pecorino Romano", "Peekskill Pyramid",
+ "Pelardon des Cevennes", "Pelardon des Corbieres", "Penamellera", "Penbryn",
+ "Pencarreg", "Perail de Brebis", "Petit Morin", "Petit Pardou", "Petit-Suisse",
+ "Picodon de Chevre", "Picos de Europa", "Piora", "Pithtviers au Foin",
+ "Plateau de Herve", "Plymouth Cheese", "Podhalanski", "Poivre d'Ane", "Polkolbin",
+ "Pont l'Eveque", "Port Nicholson", "Port-Salut", "Postel", "Pouligny-Saint-Pierre",
+ "Pourly", "Prastost", "Pressato", "Prince-Jean", "Processed Cheddar", "Provolone",
+ "Provolone (Australian)", "Pyengana Cheddar", "Pyramide", "Quark",
+ "Quark (Australian)", "Quartirolo Lombardo", "Quatre-Vents", "Quercy Petit",
+ "Queso Blanco", "Queso Blanco con Frutas --Pina y Mango", "Queso de Murcia",
+ "Queso del Montsec", "Queso del Tietar", "Queso Fresco", "Queso Fresco (Adobera)",
+ "Queso Iberico", "Queso Jalapeno", "Queso Majorero", "Queso Media Luna",
+ "Queso Para Frier", "Queso Quesadilla", "Rabacal", "Raclette", "Ragusano", "Raschera",
+ "Reblochon", "Red Leicester", "Regal de la Dombes", "Reggianito", "Remedou",
+ "Requeson", "Richelieu", "Ricotta", "Ricotta (Australian)", "Ricotta Salata", "Ridder",
+ "Rigotte", "Rocamadour", "Rollot", "Romano", "Romans Part Dieu", "Roncal", "Roquefort",
+ "Roule", "Rouleau De Beaulieu", "Royalp Tilsit", "Rubens", "Rustinu", "Saaland Pfarr",
+ "Saanenkaese", "Saga", "Sage Derby", "Sainte Maure", "Saint-Marcellin",
+ "Saint-Nectaire", "Saint-Paulin", "Salers", "Samso", "San Simon", "Sancerre",
+ "Sap Sago", "Sardo", "Sardo Egyptian", "Sbrinz", "Scamorza", "Schabzieger", "Schloss",
+ "Selles sur Cher", "Selva", "Serat", "Seriously Strong Cheddar", "Serra da Estrela",
+ "Sharpam", "Shelburne Cheddar", "Shropshire Blue", "Siraz", "Sirene", "Smoked Gouda",
+ "Somerset Brie", "Sonoma Jack", "Sottocenare al Tartufo", "Soumaintrain",
+ "Sourire Lozerien", "Spenwood", "Sraffordshire Organic", "St. Agur Blue Cheese",
+ "Stilton", "Stinking Bishop", "String", "Sussex Slipcote", "Sveciaost", "Swaledale",
+ "Sweet Style Swiss", "Swiss", "Syrian (Armenian String)", "Tala", "Taleggio", "Tamie",
+ "Tasmania Highland Chevre Log", "Taupiniere", "Teifi", "Telemea", "Testouri",
+ "Tete de Moine", "Tetilla", "Texas Goat Cheese", "Tibet", "Tillamook Cheddar",
+ "Tilsit", "Timboon Brie", "Toma", "Tomme Brulee", "Tomme d'Abondance",
+ "Tomme de Chevre", "Tomme de Romans", "Tomme de Savoie", "Tomme des Chouans", "Tommes",
+ "Torta del Casar", "Toscanello", "Touree de L'Aubier", "Tourmalet",
+ "Trappe (Veritable)", "Trois Cornes De Vendee", "Tronchon", "Trou du Cru", "Truffe",
+ "Tupi", "Turunmaa", "Tymsboro", "Tyn Grug", "Tyning", "Ubriaco", "Ulloa",
+ "Vacherin-Fribourgeois", "Valencay", "Vasterbottenost", "Venaco", "Vendomois",
+ "Vieux Corse", "Vignotte", "Vulscombe", "Waimata Farmhouse Blue",
+ "Washed Rind Cheese (Australian)", "Waterloo", "Weichkaese", "Wellington",
+ "Wensleydale", "White Stilton", "Whitestone Farmhouse", "Wigmore", "Woodside Cabecou",
+ "Xanadu", "Xynotyro", "Yarg Cornish", "Yarra Valley Pyramid", "Yorkshire Blue",
+ "Zamorano", "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"
+ };
+}
diff --git a/samples/browseable/CustomChoiceList/src/com.example.android.customchoicelist/MainActivity.java b/samples/browseable/CustomChoiceList/src/com.example.android.customchoicelist/MainActivity.java
new file mode 100755
index 000000000..e4e89f234
--- /dev/null
+++ b/samples/browseable/CustomChoiceList/src/com.example.android.customchoicelist/MainActivity.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * 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.example.android.customchoicelist;
+
+import android.app.ListActivity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+/**
+ * This sample demonstrates how to create custom single- or multi-choice
+ * {@link android.widget.ListView} UIs. The most interesting bits are in
+ * the
+
+ This sample demonstrates notifications with custom content views.
+
+ On API level 16 and above a big content view is also defined that is used for the
+ * 'expanded' notification. The notification is created by the NotificationCompat.Builder.
+ * The expanded content view is set directly on the {@link android.app.Notification} once it has been build.
+ * (See {@link android.app.Notification#bigContentView}.) The content views are inflated as {@link android.widget.RemoteViews} directly from their XML layout
+ * definitions using {@link android.widget.RemoteViews#RemoteViews(String, int)}.
+
+ This sample demonstrates two alternative presentations of the
+ action bar that are well-suited for simple data entry scenarios.
+
+ In this presentation, a done bar replaces the action
+ bar entirely, providing two direct actions to persist or dismiss changes. This is
+ suitable for cases where no additional view details or actions are needed in the
+ action bar.
+
+
+
+ This sample demonstrates how to implement horizontal paging between fragments in
+ applications that use ActionBar, using a ViewPager widget.
+
+ A {@link SectionsPagerAdapter} will be instantiated to hold the different pages of
+ * fragments that are to be displayed. A
+ * {@link android.support.v4.view.ViewPager.SimpleOnPageChangeListener} will also be configured
+ * to receive callbacks when the user swipes between pages in the ViewPager.
+ *
+ * @param savedInstanceState
+ */
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ // Load the UI from res/layout/activity_main.xml
+ setContentView(R.layout.sample_main);
+
+ // Set up the action bar. The navigation mode is set to NAVIGATION_MODE_TABS, which will
+ // cause the ActionBar to render a set of tabs. Note that these tabs are *not* rendered
+ // by the ViewPager; additional logic is lower in this file to synchronize the ViewPager
+ // state with the tab state. (See mViewPager.setOnPageChangeListener() and onTabSelected().)
+ // BEGIN_INCLUDE (set_navigation_mode)
+ final ActionBar actionBar = getActionBar();
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
+ // END_INCLUDE (set_navigation_mode)
+
+ // BEGIN_INCLUDE (setup_view_pager)
+ // Create the adapter that will return a fragment for each of the three primary sections
+ // of the app.
+ mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
+
+ // Set up the ViewPager with the sections adapter.
+ mViewPager = (ViewPager) findViewById(R.id.pager);
+ mViewPager.setAdapter(mSectionsPagerAdapter);
+ // END_INCLUDE (setup_view_pager)
+
+ // When swiping between different sections, select the corresponding tab. We can also use
+ // ActionBar.Tab#select() to do this if we have a reference to the Tab.
+ // BEGIN_INCLUDE (page_change_listener)
+ mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
+ @Override
+ public void onPageSelected(int position) {
+ actionBar.setSelectedNavigationItem(position);
+ }
+ });
+ // END_INCLUDE (page_change_listener)
+
+ // BEGIN_INCLUDE (add_tabs)
+ // For each of the sections in the app, add a tab to the action bar.
+ for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
+ // Create a tab with text corresponding to the page title defined by the adapter. Also
+ // specify this Activity object, which implements the TabListener interface, as the
+ // callback (listener) for when this tab is selected.
+ actionBar.addTab(
+ actionBar.newTab()
+ .setText(mSectionsPagerAdapter.getPageTitle(i))
+ .setTabListener(this));
+ }
+ // END_INCLUDE (add_tabs)
+ }
+
+ /**
+ * Update {@link ViewPager} after a tab has been selected in the ActionBar.
+ *
+ * @param tab Tab that was selected.
+ * @param fragmentTransaction A {@link android.app.FragmentTransaction} for queuing fragment operations to
+ * execute once this method returns. This FragmentTransaction does
+ * not support being added to the back stack.
+ */
+ // BEGIN_INCLUDE (on_tab_selected)
+ @Override
+ public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+ // When the given tab is selected, tell the ViewPager to switch to the corresponding page.
+ mViewPager.setCurrentItem(tab.getPosition());
+ }
+ // END_INCLUDE (on_tab_selected)
+
+ /**
+ * Unused. Required for {@link android.app.ActionBar.TabListener}.
+ */
+ @Override
+ public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+ }
+
+ /**
+ * Unused. Required for {@link android.app.ActionBar.TabListener}.
+ */
+ @Override
+ public void onTabReselected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
+ }
+
+ // BEGIN_INCLUDE (fragment_pager_adapter)
+ /**
+ * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
+ * one of the sections/tabs/pages. This provides the data for the {@link ViewPager}.
+ */
+ public class SectionsPagerAdapter extends FragmentPagerAdapter {
+ // END_INCLUDE (fragment_pager_adapter)
+
+ public SectionsPagerAdapter(FragmentManager fm) {
+ super(fm);
+ }
+
+ // BEGIN_INCLUDE (fragment_pager_adapter_getitem)
+ /**
+ * Get fragment corresponding to a specific position. This will be used to populate the
+ * contents of the {@link ViewPager}.
+ *
+ * @param position Position to fetch fragment for.
+ * @return Fragment for specified position.
+ */
+ @Override
+ public Fragment getItem(int position) {
+ // getItem is called to instantiate the fragment for the given page.
+ // Return a DummySectionFragment (defined as a static inner class
+ // below) with the page number as its lone argument.
+ Fragment fragment = new DummySectionFragment();
+ Bundle args = new Bundle();
+ args.putInt(DummySectionFragment.ARG_SECTION_NUMBER, position + 1);
+ fragment.setArguments(args);
+ return fragment;
+ }
+ // END_INCLUDE (fragment_pager_adapter_getitem)
+
+ // BEGIN_INCLUDE (fragment_pager_adapter_getcount)
+ /**
+ * Get number of pages the {@link ViewPager} should render.
+ *
+ * @return Number of fragments to be rendered as pages.
+ */
+ @Override
+ public int getCount() {
+ // Show 3 total pages.
+ return 3;
+ }
+ // END_INCLUDE (fragment_pager_adapter_getcount)
+
+ // BEGIN_INCLUDE (fragment_pager_adapter_getpagetitle)
+ /**
+ * Get title for each of the pages. This will be displayed on each of the tabs.
+ *
+ * @param position Page to fetch title for.
+ * @return Title for specified page.
+ */
+ @Override
+ public CharSequence getPageTitle(int position) {
+ Locale l = Locale.getDefault();
+ switch (position) {
+ case 0:
+ return getString(R.string.title_section1).toUpperCase(l);
+ case 1:
+ return getString(R.string.title_section2).toUpperCase(l);
+ case 2:
+ return getString(R.string.title_section3).toUpperCase(l);
+ }
+ return null;
+ }
+ // END_INCLUDE (fragment_pager_adapter_getpagetitle)
+ }
+
+ /**
+ * A dummy fragment representing a section of the app, but that simply displays dummy text.
+ * This would be replaced with your application's content.
+ */
+ public static class DummySectionFragment extends Fragment {
+ /**
+ * The fragment argument representing the section number for this
+ * fragment.
+ */
+ public static final String ARG_SECTION_NUMBER = "section_number";
+
+ public DummySectionFragment() {
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View rootView = inflater.inflate(R.layout.fragment_main_dummy, container, false);
+ TextView dummyTextView = (TextView) rootView.findViewById(R.id.section_label);
+ dummyTextView.setText(Integer.toString(getArguments().getInt(ARG_SECTION_NUMBER)));
+ return rootView;
+ }
+ }
+
+}
diff --git a/samples/browseable/ImmersiveMode/AndroidManifest.xml b/samples/browseable/ImmersiveMode/AndroidManifest.xml
new file mode 100644
index 000000000..72a60ce15
--- /dev/null
+++ b/samples/browseable/ImmersiveMode/AndroidManifest.xml
@@ -0,0 +1,40 @@
+
+
+
+
+ One of the features introduced in KitKat is "immersive mode". Immersive mode gives the
+ user the ability to show/hide the status bar and navigation bar with a swipe. To try,
+ click the "Toggle immersive mode" button, then try swiping the bar in and out!
+
+ When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.
+
+ This sample shows you how to use {@link android.support.v7.widget.PopupMenu PopupMenu}
+ from ActionBarCompat to create a list, with each item having a dropdown menu.
+
+
+ * The interesting part of this sample is in {@link PopupListFragment}.
+ *
+ * This Activity extends from {@link ActionBarActivity}, which provides all of the function
+ * necessary to display a compatible Action Bar on devices running Android v2.1+.
+ */
+public class MainActivity extends ActionBarActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Set content view (which contains a PopupListFragment)
+ setContentView(R.layout.sample_main);
+ }
+
+}
diff --git a/samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/PopupListFragment.java b/samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/PopupListFragment.java
new file mode 100644
index 000000000..754bf224e
--- /dev/null
+++ b/samples/browseable/ListPopupMenu/src/com.example.android.actionbarcompat.listpopupmenu/PopupListFragment.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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.example.android.actionbarcompat.listpopupmenu;
+
+import android.os.Bundle;
+import android.support.v4.app.ListFragment;
+import android.support.v7.widget.PopupMenu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.Toast;
+
+import java.util.ArrayList;
+
+/**
+ * This ListFragment displays a list of cheeses, with a clickable view on each item whichs displays
+ * a {@link android.support.v7.widget.PopupMenu PopupMenu} when clicked, allowing the user to
+ * remove the item from the list.
+ */
+public class PopupListFragment extends ListFragment implements View.OnClickListener {
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+
+ // We want to allow modifications to the list so copy the dummy data array into an ArrayList
+ ArrayList
+
+ This sample demonstrates how to connect to the network and fetch raw HTML using
+ HttpURLConnection. AsyncTask is used to perform the fetch on a background thread.
+
+ When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.
+
+ This sample shows you how a provide a context-sensitive ShareActionProvider with
+ ActionBarCompat, backwards compatible to API v7.
+
+
+ * The sample contains a {@link ViewPager} which displays content of differing types: image and
+ * text. When a new item is selected in the ViewPager, the ShareActionProvider is updated with
+ * a share intent specific to that content.
+ *
+ * This Activity extends from {@link ActionBarActivity}, which provides all of the function
+ * necessary to display a compatible Action Bar on devices running Android v2.1+.
+ */
+public class MainActivity extends ActionBarActivity {
+
+ // The items to be displayed in the ViewPager
+ private final ArrayList
+
+ Using the OPEN_DOCUMENT intent, a client app can access a list of Document Providers
+ on the device, and choose a file from any of them.
+ \n\nTo demonstrate this, click the button below to open up the Storage Access Framework
+ interface, and choose an image on your device. It will be displayed in this app.
+
+ When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.
+
+ This sample shows you how to use ActionBarCompat with a customized theme. It utilizes a
+ split action bar when running on a device with a narrow display, and show three tabs.
+
+
+
+ This sample illustrates how links can be added to a TextView. This can be done either
+ automatically by setting the "autoLink" property or explicitly.
+
+ When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode. This can be done in three ways:
+ *
+
+ This sample illustrates the use of a TextSwitcher to display text.
+ \n\nClick the button below to set new text in the TextSwitcher and observe the
+ in and out fade animations.
+
+ When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.
+
+ Introductory text that explains what the sample is intended to demonstrate. Edit
+ in template-params.xml.
+
+ When this is set as the head of the list,
+ * an instance of it can function as a drop-in replacement for {@link android.util.Log}.
+ * Most of the methods in this class server only to map a method call in Log to its equivalent
+ * in LogNode.
+ * 2. For each item, check if it's in the incoming data.
+ * a. YES: Remove from "incoming" list. Check if data has mutated, if so, perform
+ * database UPDATE.
+ * b. NO: Schedule DELETE from database.
+ * (At this point, incoming database only contains missing items.)
+ * 3. For any items remaining in incoming list, ADD to database.
+ */
+ public void updateLocalFeedData(final InputStream stream, final SyncResult syncResult)
+ throws IOException, XmlPullParserException, RemoteException,
+ OperationApplicationException, ParseException {
+ final FeedParser feedParser = new FeedParser();
+ final ContentResolver contentResolver = getContext().getContentResolver();
+
+ Log.i(TAG, "Parsing stream as Atom feed");
+ final List
+ * SelectionBuilder builder = new SelectionBuilder();
+ * Cursor c = builder.table(FeedContract.Entry.TABLE_NAME) // String TABLE_NAME = "entry"
+ * .where(FeedContract.Entry._ID + "=?", id); // String _ID = "_ID"
+ * .query(db, projection, sortOrder)
+ *
+ *
+ *
+ *
+ * // String SESSIONS_JOIN_BLOCKS_ROOMS = "sessions "
+ * // + "LEFT OUTER JOIN blocks ON sessions.block_id=blocks.block_id "
+ * // + "LEFT OUTER JOIN rooms ON sessions.room_id=rooms.room_id";
+ *
+ * // String Subquery.BLOCK_NUM_STARRED_SESSIONS =
+ * // "(SELECT COUNT(1) FROM "
+ * // + Tables.SESSIONS + " WHERE " + Qualified.SESSIONS_BLOCK_ID + "="
+ * // + Qualified.BLOCKS_BLOCK_ID + " AND " + Qualified.SESSIONS_STARRED + "=1)";
+ *
+ * String Subqery.BLOCK_SESSIONS_COUNT =
+ * Cursor c = builder.table(Tables.SESSIONS_JOIN_BLOCKS_ROOMS)
+ * .map(Blocks.NUM_STARRED_SESSIONS, Subquery.BLOCK_NUM_STARRED_SESSIONS)
+ * .mapToTable(Sessions._ID, Tables.SESSIONS)
+ * .mapToTable(Sessions.SESSION_ID, Tables.SESSIONS)
+ * .mapToTable(Sessions.BLOCK_ID, Tables.SESSIONS)
+ * .mapToTable(Sessions.ROOM_ID, Tables.SESSIONS)
+ * .where(Qualified.SESSIONS_BLOCK_ID + "=?", blockId);
+ *
+ *
+ *
+ * .where("blog_posts.category = 'PROGRAMMING');
+ *
+ *
+ *
+ * .where("blog_posts.title contains ?, userSearchString);
+ *
+ *
+ * @param selection SQL where statement
+ * @param selectionArgs Values to substitute for positional parameters ('?' characters in
+ * {@code selection} statement. Will be automatically escaped.
+ * @return Fluent interface
+ */
+ public SelectionBuilder where(String selection, String... selectionArgs) {
+ if (TextUtils.isEmpty(selection)) {
+ if (selectionArgs != null && selectionArgs.length > 0) {
+ throw new IllegalArgumentException(
+ "Valid selection required when including arguments=");
+ }
+
+ // Shortcut when clause is empty
+ return this;
+ }
+
+ if (mSelection.length() > 0) {
+ mSelection.append(" AND ");
+ }
+
+ mSelection.append("(").append(selection).append(")");
+ if (selectionArgs != null) {
+ Collections.addAll(mSelectionArgs, selectionArgs);
+ }
+
+ return this;
+ }
+
+ /**
+ * Table name to use for SQL {@code FROM} statement.
+ *
+ * res/layout/ directory of this sample.
+ */
+public class MainActivity extends ListActivity {
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.sample_main);
+ setListAdapter(new MyAdapter());
+ }
+
+ /**
+ * A simple array adapter that creates a list of cheeses.
+ */
+ private class MyAdapter extends BaseAdapter {
+ @Override
+ public int getCount() {
+ return Cheeses.CHEESES.length;
+ }
+
+ @Override
+ public String getItem(int position) {
+ return Cheeses.CHEESES[position];
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return Cheeses.CHEESES[position].hashCode();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup container) {
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(R.layout.list_item, container, false);
+ }
+
+ ((TextView) convertView.findViewById(android.R.id.text1))
+ .setText(getItem(position));
+ return convertView;
+ }
+ }
+}
diff --git a/samples/browseable/CustomNotifications/AndroidManifest.xml b/samples/browseable/CustomNotifications/AndroidManifest.xml
new file mode 100644
index 000000000..b20a41196
--- /dev/null
+++ b/samples/browseable/CustomNotifications/AndroidManifest.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+ *