├── .google └── packaging.yaml ├── Application ├── build.gradle └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ ├── android │ │ └── multiwindowplayground │ │ │ ├── MainActivity.java │ │ │ └── activities │ │ │ ├── AdjacentActivity.java │ │ │ ├── BasicActivity.java │ │ │ ├── CustomConfigurationChangeActivity.java │ │ │ ├── LaunchBoundsActivity.java │ │ │ ├── LoggingActivity.java │ │ │ ├── MinimumSizeActivity.java │ │ │ └── UnresizableActivity.java │ │ └── example │ │ └── android │ │ └── common │ │ └── logger │ │ ├── Log.java │ │ ├── LogFragment.java │ │ ├── LogNode.java │ │ ├── LogView.java │ │ ├── LogWrapper.java │ │ └── MessageOnlyLogFilter.java │ └── res │ ├── layout │ ├── activity_logging.xml │ ├── activity_main.xml │ └── logging.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── kotlinApp ├── Application │ ├── build.gradle │ └── src │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── java │ │ └── com │ │ │ └── android │ │ │ └── multiwindowplayground │ │ │ ├── MainActivity.kt │ │ │ ├── activities │ │ │ ├── AdjacentActivity.kt │ │ │ ├── BasicActivity.kt │ │ │ ├── CustomConfigurationChangeActivity.kt │ │ │ ├── LaunchBoundsActivity.kt │ │ │ ├── LoggingActivity.kt │ │ │ ├── MinimumSizeActivity.kt │ │ │ └── UnresizableActivity.kt │ │ │ └── logger │ │ │ ├── Log.kt │ │ │ ├── LogFragment.kt │ │ │ ├── LogNode.kt │ │ │ ├── LogView.kt │ │ │ ├── LogWrapper.kt │ │ │ └── MessageOnlyLogFilter.kt │ │ └── res │ │ ├── layout │ │ ├── activity_logging.xml │ │ ├── activity_main.xml │ │ └── logging.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshots │ ├── icon-web.png │ └── main.png └── settings.gradle ├── screenshots ├── icon-web.png └── main.png └── settings.gradle /.google/packaging.yaml: -------------------------------------------------------------------------------- 1 | 2 | # GOOGLE SAMPLE PACKAGING DATA 3 | # 4 | # This file is used by Google as part of our samples packaging process. 5 | # End users may safely ignore this file. It has no relevance to other systems. 6 | --- 7 | status: PUBLISHED 8 | technologies: [Android] 9 | categories: [UI] 10 | languages: [Java] 11 | solutions: [Mobile] 12 | github: android-MultiWindowPlayground 13 | level: INTERMEDIATE 14 | icon: screenshots/icon-web.png 15 | apiRefs: 16 | - android:android.content.Intent 17 | - android:android.app.ActivityOptions 18 | license: apache2 19 | -------------------------------------------------------------------------------- /Application/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | buildscript { 18 | repositories { 19 | jcenter() 20 | } 21 | 22 | dependencies { 23 | classpath 'com.android.tools.build:gradle:3.0.0' 24 | } 25 | } 26 | 27 | allprojects { 28 | repositories { 29 | jcenter() 30 | } 31 | } 32 | 33 | apply plugin: 'com.android.application' 34 | 35 | android { 36 | compileSdkVersion 24 37 | buildToolsVersion '23.0.3' 38 | 39 | defaultConfig { 40 | applicationId "com.android.multiwindowplayground" 41 | minSdkVersion 24 42 | targetSdkVersion 24 43 | versionCode 1 44 | versionName "1.0" 45 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 46 | 47 | } 48 | buildTypes { 49 | release { 50 | minifyEnabled false 51 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 52 | } 53 | } 54 | compileOptions { 55 | sourceCompatibility JavaVersion.VERSION_1_7 56 | targetCompatibility JavaVersion.VERSION_1_7 57 | } 58 | } 59 | 60 | dependencies { 61 | compile fileTree(include: ['*.jar'], dir: 'libs') 62 | testCompile 'junit:junit:4.12' 63 | compile 'com.android.support:appcompat-v7:24.0.0-beta1' 64 | androidTestCompile 'com.android.support:support-annotations:24.0.0-beta1' 65 | androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.1' 66 | } 67 | -------------------------------------------------------------------------------- /Application/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 19 | 20 | 26 | 29 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 43 | 44 | 47 | 51 | 57 | 58 | 59 | 61 | 64 | 65 | 66 | 69 | 70 | 72 | 77 | 78 | 79 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /Application/src/main/java/com/android/multiwindowplayground/MainActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.multiwindowplayground; 18 | 19 | import com.android.multiwindowplayground.activities.AdjacentActivity; 20 | import com.android.multiwindowplayground.activities.BasicActivity; 21 | import com.android.multiwindowplayground.activities.CustomConfigurationChangeActivity; 22 | import com.android.multiwindowplayground.activities.LaunchBoundsActivity; 23 | import com.android.multiwindowplayground.activities.LoggingActivity; 24 | import com.android.multiwindowplayground.activities.MinimumSizeActivity; 25 | import com.android.multiwindowplayground.activities.UnresizableActivity; 26 | 27 | import android.app.ActivityOptions; 28 | import android.content.Intent; 29 | import android.graphics.Rect; 30 | import android.os.Bundle; 31 | import android.util.Log; 32 | import android.view.View; 33 | 34 | public class MainActivity extends LoggingActivity { 35 | 36 | @Override 37 | protected void onCreate(Bundle savedInstanceState) { 38 | super.onCreate(savedInstanceState); 39 | setContentView(R.layout.activity_main); 40 | 41 | View multiDisabledMessage = findViewById(R.id.warning_multiwindow_disabled); 42 | // Display an additional message if the app is not in multiwindow mode. 43 | if (!isInMultiWindowMode()) { 44 | multiDisabledMessage.setVisibility(View.VISIBLE); 45 | } else { 46 | multiDisabledMessage.setVisibility(View.GONE); 47 | } 48 | } 49 | 50 | public void onStartUnresizableClick(View view) { 51 | Log.d(mLogTag, "** starting UnresizableActivity"); 52 | 53 | /* 54 | * This activity is marked as 'unresizable' in the AndroidManifest. We need to specify the 55 | * FLAG_ACTIVITY_NEW_TASK flag here to launch it into a new task stack, otherwise the 56 | * properties from the root activity would have been inherited (which was here marked as 57 | * resizable by default). 58 | */ 59 | Intent intent = new Intent(this, UnresizableActivity.class); 60 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 61 | startActivity(intent); 62 | } 63 | 64 | public void onStartMinimumSizeActivity(View view) { 65 | Log.d(mLogTag, "** starting MinimumSizeActivity"); 66 | 67 | startActivity(new Intent(this, MinimumSizeActivity.class)); 68 | } 69 | 70 | public void onStartAdjacentActivity(View view) { 71 | Log.d(mLogTag, "** starting AdjacentActivity"); 72 | 73 | /* 74 | * Start this activity adjacent to the focused activity (ie. this activity) if possible. 75 | * Note that this flag is just a hint to the system and may be ignored. For example, 76 | * if the activity is launched within the same task, it will be launched on top of the 77 | * previous activity that started the Intent. That's why the Intent.FLAG_ACTIVITY_NEW_TASK 78 | * flag is specified here in the intent - this will start the activity in a new task. 79 | */ 80 | Intent intent = new Intent(this, AdjacentActivity.class); 81 | intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK); 82 | startActivity(intent); 83 | } 84 | 85 | public void onStartLaunchBoundsActivity(View view) { 86 | Log.d(mLogTag, "** starting LaunchBoundsActivity"); 87 | 88 | // Define the bounds in which the Activity will be launched into. 89 | Rect bounds = new Rect(500, 300, 100, 0); 90 | 91 | // Set the bounds as an activity option. 92 | ActivityOptions options = ActivityOptions.makeBasic(); 93 | options.setLaunchBounds(bounds); 94 | 95 | // Start the LaunchBoundsActivity with the specified options 96 | Intent intent = new Intent(this, LaunchBoundsActivity.class); 97 | startActivity(intent, options.toBundle()); 98 | 99 | } 100 | 101 | public void onStartBasicActivity(View view) { 102 | Log.d(mLogTag, "** starting BasicActivity"); 103 | 104 | // Start an Activity with the default options in the 'singleTask' launch mode as defined in 105 | // the AndroidManifest.xml. 106 | startActivity(new Intent(this, BasicActivity.class)); 107 | 108 | } 109 | 110 | public void onStartCustomConfigurationActivity(View view) { 111 | Log.d(mLogTag, "** starting CustomConfigurationChangeActivity"); 112 | 113 | // Start an Activity that handles all configuration changes itself. 114 | startActivity(new Intent(this, CustomConfigurationChangeActivity.class)); 115 | 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Application/src/main/java/com/android/multiwindowplayground/activities/AdjacentActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.multiwindowplayground.activities; 18 | 19 | import com.android.multiwindowplayground.R; 20 | 21 | import android.os.Bundle; 22 | import android.view.View; 23 | 24 | /** 25 | * This Activity is to be launched adjacent to another Activity using the {@link 26 | * android.content.Intent#FLAG_ACTIVITY_LAUNCH_ADJACENT}. 27 | * 28 | * @see com.android.multiwindowplayground.MainActivity#onStartAdjacentActivity(View) 29 | */ 30 | public class AdjacentActivity extends LoggingActivity { 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(R.layout.activity_logging); 36 | 37 | setBackgroundColor(R.color.teal); 38 | setDescription(R.string.activity_adjacent_description); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Application/src/main/java/com/android/multiwindowplayground/activities/BasicActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.multiwindowplayground.activities; 18 | 19 | import com.android.multiwindowplayground.R; 20 | 21 | import android.os.Bundle; 22 | import android.view.View; 23 | 24 | /** 25 | * This activity is the most basic, simeple use case and is to be launched without any special 26 | * flags 27 | * or settings. 28 | * 29 | * @see com.android.multiwindowplayground.MainActivity#onStartBasicActivity(View) 30 | */ 31 | public class BasicActivity extends LoggingActivity { 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_logging); 37 | 38 | // Set the color and description 39 | setDescription(R.string.activity_description_basic); 40 | setBackgroundColor(R.color.gray); 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Application/src/main/java/com/android/multiwindowplayground/activities/CustomConfigurationChangeActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.multiwindowplayground.activities; 18 | 19 | import com.android.multiwindowplayground.R; 20 | 21 | import android.content.res.Configuration; 22 | import android.os.Bundle; 23 | import android.view.View; 24 | 25 | /** 26 | * This activity handles configuration changes itself. The list of configuration changes that are 27 | * supported is defined in its AndroidManifest definition. Each configuration change triggers a 28 | * call to {@link #onConfigurationChanged(Configuration)}, which is logged in the {@link 29 | * LoggingActivity}. 30 | * 31 | * @see com.android.multiwindowplayground.MainActivity#onStartCustomConfigurationActivity(View) 32 | */ 33 | public class CustomConfigurationChangeActivity extends LoggingActivity { 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.activity_logging); 39 | 40 | setBackgroundColor(R.color.cyan); 41 | setDescription(R.string.activity_custom_description); 42 | } 43 | 44 | @Override 45 | public void onConfigurationChanged(Configuration newConfig) { 46 | super.onConfigurationChanged(newConfig); 47 | 48 | /* 49 | Note: The implementation in LoggingActivity logs the output o the new configuration. 50 | This callback is received whenever the configuration is updated, for example when the 51 | size of this Activity is changed. 52 | */ 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Application/src/main/java/com/android/multiwindowplayground/activities/LaunchBoundsActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.multiwindowplayground.activities; 18 | 19 | import com.android.multiwindowplayground.R; 20 | 21 | import android.os.Bundle; 22 | import android.view.View; 23 | 24 | /** 25 | * In free-form mode, this activity is to be launched within a defined bounds on screen. 26 | * This property is set as part of the Intent that starts this activity. 27 | * 28 | * @see com.android.multiwindowplayground.MainActivity#onStartLaunchBoundsActivity(View) 29 | */ 30 | public class LaunchBoundsActivity extends LoggingActivity { 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(R.layout.activity_logging); 36 | 37 | setBackgroundColor(R.color.lime); 38 | setDescription(R.string.activity_bounds_description); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Application/src/main/java/com/android/multiwindowplayground/activities/LoggingActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.multiwindowplayground.activities; 18 | 19 | import com.android.multiwindowplayground.R; 20 | import com.example.android.common.logger.Log; 21 | import com.example.android.common.logger.LogFragment; 22 | import com.example.android.common.logger.LogWrapper; 23 | import com.example.android.common.logger.MessageOnlyLogFilter; 24 | 25 | import android.content.res.Configuration; 26 | import android.os.Bundle; 27 | import android.os.PersistableBundle; 28 | import android.support.annotation.ColorRes; 29 | import android.support.annotation.StringRes; 30 | import android.support.v7.app.AppCompatActivity; 31 | import android.view.View; 32 | import android.widget.TextView; 33 | 34 | /** 35 | * Activity that logs all key lifecycle callbacks to {@link Log}. 36 | * Output is also logged to the UI into a {@link LogFragment} through {@link #initializeLogging()} 37 | * and {@link #stopLogging()}. 38 | */ 39 | public abstract class LoggingActivity extends AppCompatActivity { 40 | 41 | protected String mLogTag = getClass().getSimpleName(); 42 | 43 | @Override 44 | protected void onCreate(Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | Log.d(mLogTag, "onCreate"); 47 | 48 | 49 | } 50 | 51 | @Override 52 | public void onPostCreate(Bundle savedInstanceState, PersistableBundle persistentState) { 53 | super.onPostCreate(savedInstanceState, persistentState); 54 | Log.d(mLogTag, "onPostCreate"); 55 | } 56 | 57 | @Override 58 | protected void onPause() { 59 | super.onPause(); 60 | Log.d(mLogTag, "onPause"); 61 | } 62 | 63 | @Override 64 | protected void onDestroy() { 65 | super.onDestroy(); 66 | Log.d(mLogTag, "onDestroy"); 67 | } 68 | 69 | @Override 70 | protected void onResume() { 71 | super.onResume(); 72 | Log.d(mLogTag, "onResume"); 73 | } 74 | 75 | @Override 76 | public void onConfigurationChanged(Configuration newConfig) { 77 | super.onConfigurationChanged(newConfig); 78 | Log.d(mLogTag, "onConfigurationChanged: " + newConfig.toString()); 79 | } 80 | 81 | @Override 82 | protected void onPostCreate(Bundle savedInstanceState) { 83 | super.onPostCreate(savedInstanceState); 84 | Log.d(mLogTag, "onPostCreate"); 85 | } 86 | 87 | @Override 88 | protected void onStart() { 89 | super.onStart(); 90 | // Start logging to UI. 91 | initializeLogging(); 92 | 93 | Log.d(mLogTag, "onStart"); 94 | } 95 | 96 | @Override 97 | protected void onStop() { 98 | super.onStop(); 99 | // Stop logging to UI when this activity is stopped. 100 | stopLogging(); 101 | 102 | Log.d(mLogTag, "onStop"); 103 | } 104 | 105 | @Override 106 | public void onMultiWindowModeChanged(boolean isInMultiWindowMode) { 107 | super.onMultiWindowModeChanged(isInMultiWindowMode); 108 | 109 | Log.d(mLogTag, "onMultiWindowModeChanged: " + isInMultiWindowMode); 110 | } 111 | 112 | // Logging and UI methods below. 113 | 114 | /** Set up targets to receive log data */ 115 | public void initializeLogging() { 116 | // Using Log, front-end to the logging chain, emulates android.util.log method signatures. 117 | // Wraps Android's native log framework 118 | LogWrapper logWrapper = new LogWrapper(); 119 | Log.setLogNode(logWrapper); 120 | 121 | // Filter strips out everything except the message text. 122 | MessageOnlyLogFilter msgFilter = new MessageOnlyLogFilter(); 123 | logWrapper.setNext(msgFilter); 124 | 125 | // On screen logging via a fragment with a TextView. 126 | LogFragment logFragment = (LogFragment) getSupportFragmentManager() 127 | .findFragmentById(R.id.log_fragment); 128 | msgFilter.setNext(logFragment.getLogView()); 129 | } 130 | 131 | public void stopLogging() { 132 | Log.setLogNode(null); 133 | } 134 | 135 | /** 136 | * Set the description text if a TextView with the id description is available. 137 | */ 138 | protected void setDescription(@StringRes int textId) { 139 | // Set the text and background color 140 | TextView description = (TextView) findViewById(R.id.description); 141 | if (description != null) { 142 | description.setText(textId); 143 | } 144 | } 145 | 146 | /** 147 | * Set the background color for the description text. 148 | */ 149 | protected void setBackgroundColor(@ColorRes int colorId) { 150 | View scrollView = findViewById(R.id.scrollview); 151 | if (scrollView != null) { 152 | scrollView.setBackgroundResource(colorId); 153 | } 154 | } 155 | 156 | } 157 | -------------------------------------------------------------------------------- /Application/src/main/java/com/android/multiwindowplayground/activities/MinimumSizeActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.multiwindowplayground.activities; 18 | 19 | import com.android.multiwindowplayground.R; 20 | 21 | import android.os.Bundle; 22 | import android.view.View; 23 | 24 | /** 25 | * This Activity has a minimum size defined in the AndroidManifeset. 26 | * 27 | * @see com.android.multiwindowplayground.MainActivity#onStartMinimumSizeActivity(View) 28 | */ 29 | public class MinimumSizeActivity extends LoggingActivity { 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.activity_logging); 35 | 36 | setBackgroundColor(R.color.pink); 37 | setDescription(R.string.activity_minimum_description); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Application/src/main/java/com/android/multiwindowplayground/activities/UnresizableActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.android.multiwindowplayground.activities; 18 | 19 | import com.android.multiwindowplayground.R; 20 | 21 | import android.os.Bundle; 22 | import android.view.View; 23 | 24 | /** 25 | * This Activity is defined as unresizable in the AndroidManifest. 26 | * This means that this activity is always launched full screen and will not be resized by the 27 | * system. 28 | * 29 | * @see com.android.multiwindowplayground.MainActivity#onStartUnresizableClick(View) 30 | */ 31 | public class UnresizableActivity extends LoggingActivity { 32 | 33 | @Override 34 | protected void onCreate(Bundle savedInstanceState) { 35 | super.onCreate(savedInstanceState); 36 | setContentView(R.layout.activity_logging); 37 | 38 | setBackgroundColor(R.color.purple); 39 | setDescription(R.string.activity_description_unresizable); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Application/src/main/java/com/example/android/common/logger/Log.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.android.common.logger; 17 | 18 | /** 19 | * Helper class for a list (or tree) of LoggerNodes. 20 | * 21 | *

When this is set as the head of the list, 22 | * an instance of it can function as a drop-in replacement for {@link android.util.Log}. 23 | * Most of the methods in this class server only to map a method call in Log to its equivalent 24 | * in LogNode.

25 | */ 26 | public class Log { 27 | 28 | // Grabbing the native values from Android's native logging facilities, 29 | // to make for easy migration and interop. 30 | public static final int NONE = -1; 31 | public static final int VERBOSE = android.util.Log.VERBOSE; 32 | public static final int DEBUG = android.util.Log.DEBUG; 33 | public static final int INFO = android.util.Log.INFO; 34 | public static final int WARN = android.util.Log.WARN; 35 | public static final int ERROR = android.util.Log.ERROR; 36 | public static final int ASSERT = android.util.Log.ASSERT; 37 | 38 | // Stores the beginning of the LogNode topology. 39 | private static LogNode mLogNode; 40 | 41 | /** 42 | * Returns the next LogNode in the linked list. 43 | */ 44 | public static LogNode getLogNode() { 45 | return mLogNode; 46 | } 47 | 48 | /** 49 | * Sets the LogNode data will be sent to. 50 | */ 51 | public static void setLogNode(LogNode node) { 52 | mLogNode = node; 53 | } 54 | 55 | /** 56 | * Instructs the LogNode to print the log data provided. Other LogNodes can 57 | * be chained to the end of the LogNode as desired. 58 | * 59 | * @param priority Log level of the data being logged. Verbose, Error, etc. 60 | * @param tag Tag for for the log data. Can be used to organize log statements. 61 | * @param msg The actual message to be logged. 62 | * @param tr If an exception was thrown, this can be sent along for the logging 63 | * facilities 64 | * to extract and print useful information. 65 | */ 66 | public static void println(int priority, String tag, String msg, Throwable tr) { 67 | if (mLogNode != null) { 68 | mLogNode.println(priority, tag, msg, tr); 69 | } 70 | } 71 | 72 | /** 73 | * Instructs the LogNode to print the log data provided. Other LogNodes can 74 | * be chained to the end of the LogNode as desired. 75 | * 76 | * @param priority Log level of the data being logged. Verbose, Error, etc. 77 | * @param tag Tag for for the log data. Can be used to organize log statements. 78 | * @param msg The actual message to be logged. The actual message to be logged. 79 | */ 80 | public static void println(int priority, String tag, String msg) { 81 | println(priority, tag, msg, null); 82 | } 83 | 84 | /** 85 | * Prints a message at VERBOSE priority. 86 | * 87 | * @param tag Tag for for the log data. Can be used to organize log statements. 88 | * @param msg The actual message to be logged. 89 | * @param tr If an exception was thrown, this can be sent along for the logging facilities 90 | * to extract and print useful information. 91 | */ 92 | public static void v(String tag, String msg, Throwable tr) { 93 | println(VERBOSE, tag, msg, tr); 94 | } 95 | 96 | /** 97 | * Prints a message at VERBOSE priority. 98 | * 99 | * @param tag Tag for for the log data. Can be used to organize log statements. 100 | * @param msg The actual message to be logged. 101 | */ 102 | public static void v(String tag, String msg) { 103 | v(tag, msg, null); 104 | } 105 | 106 | 107 | /** 108 | * Prints a message at DEBUG priority. 109 | * 110 | * @param tag Tag for for the log data. Can be used to organize log statements. 111 | * @param msg The actual message to be logged. 112 | * @param tr If an exception was thrown, this can be sent along for the logging facilities 113 | * to extract and print useful information. 114 | */ 115 | public static void d(String tag, String msg, Throwable tr) { 116 | println(DEBUG, tag, msg, tr); 117 | } 118 | 119 | /** 120 | * Prints a message at DEBUG priority. 121 | * 122 | * @param tag Tag for for the log data. Can be used to organize log statements. 123 | * @param msg The actual message to be logged. 124 | */ 125 | public static void d(String tag, String msg) { 126 | d(tag, msg, null); 127 | } 128 | 129 | /** 130 | * Prints a message at INFO priority. 131 | * 132 | * @param tag Tag for for the log data. Can be used to organize log statements. 133 | * @param msg The actual message to be logged. 134 | * @param tr If an exception was thrown, this can be sent along for the logging facilities 135 | * to extract and print useful information. 136 | */ 137 | public static void i(String tag, String msg, Throwable tr) { 138 | println(INFO, tag, msg, tr); 139 | } 140 | 141 | /** 142 | * Prints a message at INFO priority. 143 | * 144 | * @param tag Tag for for the log data. Can be used to organize log statements. 145 | * @param msg The actual message to be logged. 146 | */ 147 | public static void i(String tag, String msg) { 148 | i(tag, msg, null); 149 | } 150 | 151 | /** 152 | * Prints a message at WARN priority. 153 | * 154 | * @param tag Tag for for the log data. Can be used to organize log statements. 155 | * @param msg The actual message to be logged. 156 | * @param tr If an exception was thrown, this can be sent along for the logging facilities 157 | * to extract and print useful information. 158 | */ 159 | public static void w(String tag, String msg, Throwable tr) { 160 | println(WARN, tag, msg, tr); 161 | } 162 | 163 | /** 164 | * Prints a message at WARN priority. 165 | * 166 | * @param tag Tag for for the log data. Can be used to organize log statements. 167 | * @param msg The actual message to be logged. 168 | */ 169 | public static void w(String tag, String msg) { 170 | w(tag, msg, null); 171 | } 172 | 173 | /** 174 | * Prints a message at WARN priority. 175 | * 176 | * @param tag Tag for for the log data. Can be used to organize log statements. 177 | * @param tr If an exception was thrown, this can be sent along for the logging facilities 178 | * to extract and print useful information. 179 | */ 180 | public static void w(String tag, Throwable tr) { 181 | w(tag, null, tr); 182 | } 183 | 184 | /** 185 | * Prints a message at ERROR priority. 186 | * 187 | * @param tag Tag for for the log data. Can be used to organize log statements. 188 | * @param msg The actual message to be logged. 189 | * @param tr If an exception was thrown, this can be sent along for the logging facilities 190 | * to extract and print useful information. 191 | */ 192 | public static void e(String tag, String msg, Throwable tr) { 193 | println(ERROR, tag, msg, tr); 194 | } 195 | 196 | /** 197 | * Prints a message at ERROR priority. 198 | * 199 | * @param tag Tag for for the log data. Can be used to organize log statements. 200 | * @param msg The actual message to be logged. 201 | */ 202 | public static void e(String tag, String msg) { 203 | e(tag, msg, null); 204 | } 205 | 206 | /** 207 | * Prints a message at ASSERT priority. 208 | * 209 | * @param tag Tag for for the log data. Can be used to organize log statements. 210 | * @param msg The actual message to be logged. 211 | * @param tr If an exception was thrown, this can be sent along for the logging facilities 212 | * to extract and print useful information. 213 | */ 214 | public static void wtf(String tag, String msg, Throwable tr) { 215 | println(ASSERT, tag, msg, tr); 216 | } 217 | 218 | /** 219 | * Prints a message at ASSERT priority. 220 | * 221 | * @param tag Tag for for the log data. Can be used to organize log statements. 222 | * @param msg The actual message to be logged. 223 | */ 224 | public static void wtf(String tag, String msg) { 225 | wtf(tag, msg, null); 226 | } 227 | 228 | /** 229 | * Prints a message at ASSERT priority. 230 | * 231 | * @param tag Tag for for the log data. Can be used to organize log statements. 232 | * @param tr If an exception was thrown, this can be sent along for the logging facilities 233 | * to extract and print useful information. 234 | */ 235 | public static void wtf(String tag, Throwable tr) { 236 | wtf(tag, null, tr); 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /Application/src/main/java/com/example/android/common/logger/LogFragment.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | 18 | package com.example.android.common.logger; 19 | 20 | import android.graphics.Typeface; 21 | import android.os.Bundle; 22 | import android.support.v4.app.Fragment; 23 | import android.text.Editable; 24 | import android.text.TextWatcher; 25 | import android.view.Gravity; 26 | import android.view.LayoutInflater; 27 | import android.view.View; 28 | import android.view.ViewGroup; 29 | import android.widget.ScrollView; 30 | 31 | /** 32 | * Simple fraggment which contains a LogView and uses is to output log data it receives 33 | * through the LogNode interface. 34 | */ 35 | public class LogFragment extends Fragment { 36 | 37 | private LogView mLogView; 38 | private ScrollView mScrollView; 39 | 40 | public LogFragment() { 41 | } 42 | 43 | public View inflateViews() { 44 | mScrollView = new ScrollView(getActivity()); 45 | ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams( 46 | ViewGroup.LayoutParams.MATCH_PARENT, 47 | ViewGroup.LayoutParams.MATCH_PARENT); 48 | mScrollView.setLayoutParams(scrollParams); 49 | 50 | mLogView = new LogView(getActivity()); 51 | ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams); 52 | logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT; 53 | mLogView.setTextAppearance(android.R.style.TextAppearance_Material_Medium); 54 | mLogView.setLayoutParams(logParams); 55 | mLogView.setClickable(true); 56 | mLogView.setFocusable(true); 57 | mLogView.setTypeface(Typeface.create("monospace", Typeface.NORMAL)); 58 | 59 | // Want to set padding as 16 dips, setPadding takes pixels. Hooray math! 60 | int paddingDips = 16; 61 | double scale = getResources().getDisplayMetrics().density; 62 | int paddingPixels = (int) ((paddingDips * (scale)) + .5); 63 | mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels); 64 | mLogView.setCompoundDrawablePadding(paddingPixels); 65 | 66 | mLogView.setGravity(Gravity.BOTTOM); 67 | 68 | mScrollView.addView(mLogView); 69 | return mScrollView; 70 | } 71 | 72 | @Override 73 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 74 | Bundle savedInstanceState) { 75 | 76 | View result = inflateViews(); 77 | 78 | mLogView.addTextChangedListener(new TextWatcher() { 79 | @Override 80 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 81 | } 82 | 83 | @Override 84 | public void onTextChanged(CharSequence s, int start, int before, int count) { 85 | } 86 | 87 | @Override 88 | public void afterTextChanged(Editable s) { 89 | 90 | mScrollView.post(new Runnable() { 91 | @Override 92 | public void run() { 93 | mScrollView 94 | .smoothScrollTo(0, mScrollView.getBottom() + mLogView.getHeight()); 95 | } 96 | }); 97 | } 98 | }); 99 | return result; 100 | } 101 | 102 | public LogView getLogView() { 103 | return mLogView; 104 | } 105 | } -------------------------------------------------------------------------------- /Application/src/main/java/com/example/android/common/logger/LogNode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.android.common.logger; 17 | 18 | /** 19 | * Basic interface for a logging system that can output to one or more targets. 20 | * Note that in addition to classes that will output these logs in some format, 21 | * one can also implement this interface over a filter and insert that in the chain, 22 | * such that no targets further down see certain data, or see manipulated forms of the data. 23 | * You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data 24 | * it received to HTML and sent it along to the next node in the chain, without printing it 25 | * anywhere. 26 | */ 27 | public interface LogNode { 28 | 29 | /** 30 | * Instructs first LogNode in the list to print the log data provided. 31 | * 32 | * @param priority Log level of the data being logged. Verbose, Error, etc. 33 | * @param tag Tag for for the log data. Can be used to organize log statements. 34 | * @param msg The actual message to be logged. The actual message to be logged. 35 | * @param tr If an exception was thrown, this can be sent along for the logging 36 | * facilities 37 | * to extract and print useful information. 38 | */ 39 | public void println(int priority, String tag, String msg, Throwable tr); 40 | 41 | } 42 | -------------------------------------------------------------------------------- /Application/src/main/java/com/example/android/common/logger/LogView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.android.common.logger; 17 | 18 | import android.app.Activity; 19 | import android.content.Context; 20 | import android.util.AttributeSet; 21 | import android.widget.TextView; 22 | 23 | /** 24 | * Simple TextView which is used to output log data received through the LogNode interface. 25 | */ 26 | public class LogView extends TextView implements LogNode { 27 | 28 | public LogView(Context context) { 29 | super(context); 30 | } 31 | 32 | public LogView(Context context, AttributeSet attrs) { 33 | super(context, attrs); 34 | } 35 | 36 | public LogView(Context context, AttributeSet attrs, int defStyle) { 37 | super(context, attrs, defStyle); 38 | } 39 | 40 | /** 41 | * Formats the log data and prints it out to the LogView. 42 | * 43 | * @param priority Log level of the data being logged. Verbose, Error, etc. 44 | * @param tag Tag for for the log data. Can be used to organize log statements. 45 | * @param msg The actual message to be logged. The actual message to be logged. 46 | * @param tr If an exception was thrown, this can be sent along for the logging 47 | * facilities 48 | * to extract and print useful information. 49 | */ 50 | @Override 51 | public void println(int priority, String tag, String msg, Throwable tr) { 52 | 53 | String priorityStr = null; 54 | 55 | // For the purposes of this View, we want to print the priority as readable text. 56 | switch (priority) { 57 | case android.util.Log.VERBOSE: 58 | priorityStr = "VERBOSE"; 59 | break; 60 | case android.util.Log.DEBUG: 61 | priorityStr = "DEBUG"; 62 | break; 63 | case android.util.Log.INFO: 64 | priorityStr = "INFO"; 65 | break; 66 | case android.util.Log.WARN: 67 | priorityStr = "WARN"; 68 | break; 69 | case android.util.Log.ERROR: 70 | priorityStr = "ERROR"; 71 | break; 72 | case android.util.Log.ASSERT: 73 | priorityStr = "ASSERT"; 74 | break; 75 | default: 76 | break; 77 | } 78 | 79 | // Handily, the Log class has a facility for converting a stack trace into a usable string. 80 | String exceptionStr = null; 81 | if (tr != null) { 82 | exceptionStr = android.util.Log.getStackTraceString(tr); 83 | } 84 | 85 | // Take the priority, tag, message, and exception, and concatenate as necessary 86 | // into one usable line of text. 87 | final StringBuilder outputBuilder = new StringBuilder(); 88 | 89 | String delimiter = "\t"; 90 | appendIfNotNull(outputBuilder, priorityStr, delimiter); 91 | appendIfNotNull(outputBuilder, tag, delimiter); 92 | appendIfNotNull(outputBuilder, msg, delimiter); 93 | appendIfNotNull(outputBuilder, exceptionStr, delimiter); 94 | 95 | // In case this was originally called from an AsyncTask or some other off-UI thread, 96 | // make sure the update occurs within the UI thread. 97 | ((Activity) getContext()).runOnUiThread((new Thread(new Runnable() { 98 | @Override 99 | public void run() { 100 | // Display the text we just generated within the LogView. 101 | appendToLog(outputBuilder.toString()); 102 | } 103 | }))); 104 | 105 | if (mNext != null) { 106 | mNext.println(priority, tag, msg, tr); 107 | } 108 | } 109 | 110 | public LogNode getNext() { 111 | return mNext; 112 | } 113 | 114 | public void setNext(LogNode node) { 115 | mNext = node; 116 | } 117 | 118 | /** 119 | * Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since 120 | * the logger takes so many arguments that might be null, this method helps cut out some of the 121 | * agonizing tedium of writing the same 3 lines over and over. 122 | * 123 | * @param source StringBuilder containing the text to append to. 124 | * @param addStr The String to append 125 | * @param delimiter The String to separate the source and appended strings. A tab or comma, 126 | * for instance. 127 | * @return The fully concatenated String as a StringBuilder 128 | */ 129 | private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) { 130 | if (addStr != null) { 131 | if (addStr.length() == 0) { 132 | delimiter = ""; 133 | } 134 | 135 | return source.append(addStr).append(delimiter); 136 | } 137 | return source; 138 | } 139 | 140 | // The next LogNode in the chain. 141 | LogNode mNext; 142 | 143 | /** Outputs the string as a new line of log data in the LogView. */ 144 | public void appendToLog(String s) { 145 | append("\n" + s); 146 | } 147 | 148 | 149 | } 150 | -------------------------------------------------------------------------------- /Application/src/main/java/com/example/android/common/logger/LogWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.android.common.logger; 17 | 18 | import android.util.Log; 19 | 20 | /** 21 | * Helper class which wraps Android's native Log utility in the Logger interface. This way 22 | * normal DDMS output can be one of the many targets receiving and outputting logs simultaneously. 23 | */ 24 | public class LogWrapper implements LogNode { 25 | 26 | // For piping: The next node to receive Log data after this one has done its work. 27 | private LogNode mNext; 28 | 29 | /** 30 | * Returns the next LogNode in the linked list. 31 | */ 32 | public LogNode getNext() { 33 | return mNext; 34 | } 35 | 36 | /** 37 | * Sets the LogNode data will be sent to.. 38 | */ 39 | public void setNext(LogNode node) { 40 | mNext = node; 41 | } 42 | 43 | /** 44 | * Prints data out to the console using Android's native log mechanism. 45 | * 46 | * @param priority Log level of the data being logged. Verbose, Error, etc. 47 | * @param tag Tag for for the log data. Can be used to organize log statements. 48 | * @param msg The actual message to be logged. The actual message to be logged. 49 | * @param tr If an exception was thrown, this can be sent along for the logging 50 | * facilities 51 | * to extract and print useful information. 52 | */ 53 | @Override 54 | public void println(int priority, String tag, String msg, Throwable tr) { 55 | // There actually are log methods that don't take a msg parameter. For now, 56 | // if that's the case, just convert null to the empty string and move on. 57 | String useMsg = msg; 58 | if (useMsg == null) { 59 | useMsg = ""; 60 | } 61 | 62 | // If an exeption was provided, convert that exception to a usable string and attach 63 | // it to the end of the msg method. 64 | if (tr != null) { 65 | msg += "\n" + Log.getStackTraceString(tr); 66 | } 67 | 68 | // This is functionally identical to Log.x(tag, useMsg); 69 | // For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg) 70 | Log.println(priority, tag, useMsg); 71 | 72 | // If this isn't the last node in the chain, move things along. 73 | if (mNext != null) { 74 | mNext.println(priority, tag, msg, tr); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Application/src/main/java/com/example/android/common/logger/MessageOnlyLogFilter.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.example.android.common.logger; 17 | 18 | /** 19 | * Simple {@link LogNode} filter, removes everything except the message. 20 | * Useful for situations like on-screen log output where you don't want a lot of metadata 21 | * displayed, 22 | * just easy-to-read message updates as they're happening. 23 | */ 24 | public class MessageOnlyLogFilter implements LogNode { 25 | 26 | LogNode mNext; 27 | 28 | /** 29 | * Takes the "next" LogNode as a parameter, to simplify chaining. 30 | * 31 | * @param next The next LogNode in the pipeline. 32 | */ 33 | public MessageOnlyLogFilter(LogNode next) { 34 | mNext = next; 35 | } 36 | 37 | public MessageOnlyLogFilter() { 38 | } 39 | 40 | @Override 41 | public void println(int priority, String tag, String msg, Throwable tr) { 42 | if (mNext != null) { 43 | getNext().println(Log.NONE, null, msg, null); 44 | } 45 | } 46 | 47 | /** 48 | * Returns the next LogNode in the chain. 49 | */ 50 | public LogNode getNext() { 51 | return mNext; 52 | } 53 | 54 | /** 55 | * Sets the LogNode data will be sent to.. 56 | */ 57 | public void setNext(LogNode node) { 58 | mNext = node; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /Application/src/main/res/layout/activity_logging.xml: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 24 | 25 | 31 | 32 | 42 | 43 | 44 | 45 | 51 | -------------------------------------------------------------------------------- /Application/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 24 | 25 | 33 | 34 | 42 | 43 | 48 | 49 | 59 | 60 | 65 | 66 |