diff --git a/app/src/main/java/com/itsaky/androidide/DesignerActivity.java b/app/src/main/java/com/itsaky/androidide/DesignerActivity.java index 6e1d50568..4fbf39d27 100644 --- a/app/src/main/java/com/itsaky/androidide/DesignerActivity.java +++ b/app/src/main/java/com/itsaky/androidide/DesignerActivity.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. - * - * - * + * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -17,8 +15,6 @@ * along with AndroidIDE. If not, see . * **************************************************************************************/ - - package com.itsaky.androidide; import android.content.Context; @@ -68,6 +64,8 @@ public class DesignerActivity extends StudioActivity { } catch (Throwable th) { mBinding.realContainer.removeAllViews(); mBinding.realContainer.addView(createErrorText(th)); + + LOG.error (getString(R.string.err_cannot_inflate_layout)); } } @@ -88,92 +86,4 @@ public class DesignerActivity extends StudioActivity { error.setBackgroundColor(ContextCompat.getColor(this, android.R.color.white)); return error; } - - private String printRClassHierarchy () throws IllegalArgumentException, IllegalAccessException { - return printClassHierarchy(android.R.class, 0); - } - - private String printClassHierarchy (Class clazz, int indent) throws IllegalArgumentException, IllegalAccessException { - final StringBuilder sb = new StringBuilder(); - sb.append("class " + clazz.getName() + " {"); - newLineIndent(sb, ++indent); - - sb.append("fields : ["); - newLineIndent(sb, ++indent); - printFields (sb, clazz, indent); - newLineIndent(sb, --indent); - sb.append("]"); - - newLineIndent(sb, indent); - sb.append("classes : ["); - newLineIndent(sb, ++indent); - printClasses (sb, clazz, indent); - newLineIndent(sb, --indent); - sb.append("]"); - - return sb.toString(); - } - - private void newLineIndent(StringBuilder sb, int indent) { - sb.append("\n"); - sb.append(repeat(" ", indent * 4)); - } - - private void printFields(StringBuilder sb, Class clazz, int indent) throws IllegalArgumentException, IllegalAccessException { - boolean first = true; - for (Field f : clazz.getDeclaredFields()) { - if (!first) { - newLineIndent(sb, indent); - } - if(!f.isAccessible()) { - f.setAccessible(true); - } - sb.append(f.getName()); - sb.append(" = "); - if (f.getType() == int[].class) { - printIntArr(sb, (int[]) f.get(null)); - } else if (f.getType() == int.class) { - sb.append(f.get(null)); - } - first = false; - } - } - - private void printClasses(StringBuilder sb, Class clazz, int indent) throws IllegalArgumentException, IllegalAccessException { - boolean first = true; - for (Class c : clazz.getClasses()) { - if (!first) { - newLineIndent(sb, indent); - } - sb.append("class " + c.getSimpleName() + " ["); - newLineIndent(sb, ++indent); - printFields(sb, c, indent); - newLineIndent(sb, --indent); - sb.append("]"); - first = false; - } - } - - private String repeat (String to, int till) { - String result = ""; - for (int i=1;i<=till;i++) { - result += to; - } - - return result; - } - - private void printIntArr (StringBuilder sb, int[] arr) { - boolean first = true; - sb.append("["); - for (int i : arr) { - if (!first) { - sb.append(", "); - } - sb.append(i); - first = false; - } - sb.append("]"); - - } } diff --git a/app/src/main/java/com/itsaky/androidide/DownloadActivity.java b/app/src/main/java/com/itsaky/androidide/DownloadActivity.java index baef766dc..5a1a9fcaf 100644 --- a/app/src/main/java/com/itsaky/androidide/DownloadActivity.java +++ b/app/src/main/java/com/itsaky/androidide/DownloadActivity.java @@ -95,7 +95,7 @@ public class DownloadActivity extends StudioActivity { .build() .forResult(abhishekti7.unicorn.filepicker.utils.Constants.REQ_UNICORN_FILE); } catch (Throwable th){ - LOG.error("Unable to start file picker", th); + LOG.error(getString (R.string.err_cannot_start_file_picker), th); } } else if(id == binding.install.getId()) { if(choosenDir == null) { @@ -134,10 +134,10 @@ public class DownloadActivity extends StudioActivity { new Thread (reader).start(); } catch (DownloadActivity.InstallationException e) { - LOG.error("Installation error", e); + LOG.error(getString(R.string.err_installation), e); onInstallationFailed(e.exitCode); } catch (IOException e) { - LOG.error("Installation error", e); + LOG.error(getString(R.string.err_installation), e); onInstallationFailed(5); // Exit code 5 : I/O Error } } diff --git a/app/src/main/java/com/itsaky/androidide/EditorActivity.java b/app/src/main/java/com/itsaky/androidide/EditorActivity.java index ed3214749..896015025 100644 --- a/app/src/main/java/com/itsaky/androidide/EditorActivity.java +++ b/app/src/main/java/com/itsaky/androidide/EditorActivity.java @@ -270,7 +270,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F saveAll(false /* No notification */); saved = true; } catch (Throwable th) { - LOG.error(":onPause(): Failed to save files", th); + LOG.error(getString(R.string.err_cannot_save_files), th); saved = false; } @@ -1081,7 +1081,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F intent.putExtra(DesignerActivity.KEY_LAYOUT_PATH, mCurrentFile.getAbsolutePath()); startActivity(intent); } catch (Throwable th) { - LOG.error("Unable to preview layout", th); + LOG.error(getString(R.string.err_cannot_preview_layout), th); getApp().toast(R.string.msg_cannot_preview_layout, Toaster.Type.ERROR); } } diff --git a/app/src/main/java/com/itsaky/androidide/app/StudioApp.java b/app/src/main/java/com/itsaky/androidide/app/StudioApp.java index 05c1f4874..53d0219ba 100644 --- a/app/src/main/java/com/itsaky/androidide/app/StudioApp.java +++ b/app/src/main/java/com/itsaky/androidide/app/StudioApp.java @@ -92,7 +92,7 @@ public class StudioApp extends BaseApplication { mXmlCompletionService = new XMLCompletionService (mAttrInfo, mWidgetInfo); } catch (Throwable th) { - LOG.error ("Unable to start XML completion service", th); + LOG.error (getString (com.itsaky.androidide.R.string.err_init_sdkinfo), th); } }, "SDK Information Loader").start(); } diff --git a/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java b/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java index 266d8f15d..a5d18efec 100644 --- a/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java +++ b/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java @@ -33,6 +33,7 @@ import org.eclipse.lsp4j.CompletionParams; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.TextDocumentIdentifier; import org.eclipse.lsp4j.jsonrpc.messages.Either; +import com.itsaky.androidide.app.StudioApp; public class JavaAutoComplete implements AutoCompleteProvider { @@ -66,10 +67,10 @@ public class JavaAutoComplete implements AutoCompleteProvider { } } catch (Throwable th) { - LOG.error("CompletionError", th); + LOG.error(StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_completion), th); } } else { - LOG.error("Cannot compute completions for Java file. No LanguageServer implementation found."); + LOG.error(StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_no_server_implementation)); } return new ArrayList(); } diff --git a/app/src/main/java/com/itsaky/androidide/lsp/AsynchronousSocketLauncher.java b/app/src/main/java/com/itsaky/androidide/lsp/AsynchronousSocketLauncher.java index bf3a94915..c0d84f4dd 100644 --- a/app/src/main/java/com/itsaky/androidide/lsp/AsynchronousSocketLauncher.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/AsynchronousSocketLauncher.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. - * - * - * + * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -17,8 +15,6 @@ * along with AndroidIDE. If not, see . * **************************************************************************************/ - - package com.itsaky.androidide.lsp; import androidx.annotation.RequiresApi; @@ -80,4 +76,9 @@ public class AsynchronousSocketLauncher extends LSPClientLauncher { CloseUtils.closeIOQuietly(serverSocket); } + + @Override + public String getLanguageCode() { + return ""; + } } diff --git a/app/src/main/java/com/itsaky/androidide/lsp/LSPClientLauncher.java b/app/src/main/java/com/itsaky/androidide/lsp/LSPClientLauncher.java index c59718173..171d09c80 100644 --- a/app/src/main/java/com/itsaky/androidide/lsp/LSPClientLauncher.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/LSPClientLauncher.java @@ -28,6 +28,7 @@ import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import org.eclipse.lsp4j.jsonrpc.Launcher; import java.util.Locale; +import com.itsaky.androidide.app.StudioApp; /** * Launches a client for a Language server and handles connection. @@ -83,7 +84,7 @@ public abstract class LSPClientLauncher extends Thread { try { launch(); } catch (Throwable th) { - LOG.error("Error starting language server", th); + LOG.error(StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_cannot_start_server, getLanguageCode()), th); } } @@ -111,6 +112,11 @@ public abstract class LSPClientLauncher extends Thread { */ public abstract void shutdown(); + /** + * Get the language code for the server + */ + public abstract String getLanguageCode(); + /** * A listener to listen for language server start event. */ @@ -195,7 +201,7 @@ public abstract class LSPClientLauncher extends Thread { this.out.write(data.data); this.out.flush(); } catch (Throwable e) { - LOG.error ("Failed to write to LSP4J socket", e); + LOG.error (StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_cannot_write_socket), e); } } } diff --git a/app/src/main/java/com/itsaky/androidide/lsp/StandardStreamsLauncher.java b/app/src/main/java/com/itsaky/androidide/lsp/StandardStreamsLauncher.java index 4c27cd2eb..72a889488 100644 --- a/app/src/main/java/com/itsaky/androidide/lsp/StandardStreamsLauncher.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/StandardStreamsLauncher.java @@ -25,6 +25,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.concurrent.Future; import org.eclipse.lsp4j.jsonrpc.Launcher; +import com.itsaky.androidide.app.StudioApp; public class StandardStreamsLauncher extends LSPClientLauncher { @@ -56,8 +57,7 @@ public class StandardStreamsLauncher extends LSPClientLauncher { listening.get(); } catch (Throwable th) { LOG.error ( - "---> StandardStreamsLauncher <---", - "An error occured while waiting for language server process to stop", + StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_server_disconnected), th ); } @@ -79,4 +79,9 @@ public class StandardStreamsLauncher extends LSPClientLauncher { CloseUtils.closeIO(in, out); } + + @Override + public String getLanguageCode() { + return this.langCode; + } } diff --git a/app/src/main/java/com/itsaky/androidide/lsp/handlers/JLSHandler.java b/app/src/main/java/com/itsaky/androidide/lsp/handlers/JLSHandler.java index 312975181..c254f0d76 100644 --- a/app/src/main/java/com/itsaky/androidide/lsp/handlers/JLSHandler.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/handlers/JLSHandler.java @@ -78,7 +78,7 @@ public class JLSHandler implements LSPHandler { mLauncher.start(); } catch (Throwable th) { - LOG.error("Unable to start Java Language server", th); + LOG.error(StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_cannot_start_server, LSPProvider.LANGUAGE_JAVA), th); } } @@ -88,7 +88,7 @@ public class JLSHandler implements LSPHandler { final IDELanguageServer server = LSPProvider.getServerForLanguage(LSPProvider.LANGUAGE_JAVA); if (server == null) { - LOG.error ("Cannot initialize Java Language Server. Server instance is null!"); + LOG.error (StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_no_server_implementation)); return Optional.empty(); } @@ -119,7 +119,7 @@ public class JLSHandler implements LSPHandler { } return Optional.of(result); } catch (Throwable e) { - LOG.error ("An error occurred while initializing language server.", e); + LOG.error (StudioApp.getInstance().getString(com.itsaky.androidide.R.string.err_init_server), e); return Optional.empty(); } } diff --git a/app/src/main/java/com/itsaky/androidide/services/builder/BuildListener.java b/app/src/main/java/com/itsaky/androidide/services/builder/BuildListener.java index fcb7a3523..6d6b6f2c5 100644 --- a/app/src/main/java/com/itsaky/androidide/services/builder/BuildListener.java +++ b/app/src/main/java/com/itsaky/androidide/services/builder/BuildListener.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. - * - * - * + * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -17,8 +15,6 @@ * along with AndroidIDE. If not, see . * **************************************************************************************/ - - package com.itsaky.androidide.services.builder; import com.itsaky.androidide.project.IDEModule; diff --git a/app/src/main/java/com/itsaky/androidide/services/builder/IDEService.java b/app/src/main/java/com/itsaky/androidide/services/builder/IDEService.java index 9ec512577..bccd41ef1 100644 --- a/app/src/main/java/com/itsaky/androidide/services/builder/IDEService.java +++ b/app/src/main/java/com/itsaky/androidide/services/builder/IDEService.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. * - * - * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -17,7 +15,6 @@ * along with AndroidIDE. If not, see . * **************************************************************************************/ - package com.itsaky.androidide.services.builder; import androidx.annotation.StringRes; @@ -151,12 +148,12 @@ public class IDEService { text = line.replace(app.getRootDir().getAbsolutePath(), "HOME"); } if (line.contains(app.getRootDir().getParentFile().getAbsolutePath())) { - text = line.replace(app.getRootDir().getParentFile().getAbsolutePath(), "ROOT_DIR"); + text = line.replace(app.getRootDir().getParentFile().getAbsolutePath(), "ROOT"); } listener.appendOutput(currentTask, text); - if(line.contains(RUN_TASK)) { + if(line.startsWith(RUN_TASK)) { listener.onRunTask(currentTask, line.trim()); } else if(line.startsWith(STARTING_DAEMON)) { listener.onStartingGradleDaemon(currentTask); diff --git a/app/src/main/java/com/itsaky/androidide/services/builder/MainThreadBuildListener.java b/app/src/main/java/com/itsaky/androidide/services/builder/MainThreadBuildListener.java index 275820faa..8e73e6249 100644 --- a/app/src/main/java/com/itsaky/androidide/services/builder/MainThreadBuildListener.java +++ b/app/src/main/java/com/itsaky/androidide/services/builder/MainThreadBuildListener.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. - * - * - * + * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -17,8 +15,6 @@ * along with AndroidIDE. If not, see . * **************************************************************************************/ - - package com.itsaky.androidide.services.builder; import com.blankj.utilcode.util.ThreadUtils; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6ca163cfa..ed517a3bf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -275,4 +275,19 @@ Please choose default font size of editor : This will delete caches directory created by Gradle. If you delete it, the next build may take a bit longer than normal as Gradle will download required files again.\nIMPORTANT: This will also delete AAPT2. You will need to reinstall it otherwise you\'ll end up with a build failure.\n\nAre you sure you want to delete caches? + + + Installation error + Completion error + No LanguageServer implementation found. + Error initializing language server + Unable to initialize SDK Info + Unable to start file picker + Failed to parse APK metadata + Unable to save files + Unable to preview layout + Unable to inflate layout + Unable to start Language Server for: %s + Failed to write to Socket stream + Language server process unexpectedly exited. diff --git a/layout-inflater/build.gradle b/layout-inflater/build.gradle index e0920273f..1b71ff6fd 100644 --- a/layout-inflater/build.gradle +++ b/layout-inflater/build.gradle @@ -32,5 +32,6 @@ dependencies { implementation 'com.blankj:utilcodex:1.30.6' implementation 'org.jsoup:jsoup:1.14.2' + implementation project (":common") api project (':sdk-info') } diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/inflater/XMLLayoutInflater.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/inflater/XMLLayoutInflater.java index d833a402f..dd4acd74e 100644 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/inflater/XMLLayoutInflater.java +++ b/layout-inflater/src/main/java/com/itsaky/androidide/ui/inflater/XMLLayoutInflater.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. - * - * - * + * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -27,8 +25,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.StringRes; import androidx.core.content.ContextCompat; -import com.itsaky.androidide.ui.resources.ResourceTable; -import com.itsaky.androidide.ui.resources.ResourceTableFactory; import com.itsaky.androidide.ui.util.Preconditions; import com.itsaky.androidide.ui.view.IAttribute; import com.itsaky.androidide.ui.view.IAttributeAdapter; @@ -65,7 +61,6 @@ class XMLLayoutInflater extends BaseLayoutInflater { private final Set resDirs; private final AttrInfo attrInfo; private final WidgetInfo widgetInfo; - private final ResourceTable frameworkResourceTable; private final IResourceFinder resFinder; private ContextProvider contextProvider; @@ -94,9 +89,8 @@ class XMLLayoutInflater extends BaseLayoutInflater { this.widgetInfo = config.widgetInfo; this.resFinder = config.resFinder; this.contextProvider = config.contextProvider; - this.frameworkResourceTable = ResourceTableFactory.newFrameworkResourceTable(); - Preconditions.assertAllNotNull("LayoutInflater parameters cannot be null", resDirs, attrInfo, widgetInfo, resFinder, frameworkResourceTable); + Preconditions.assertAllNotNull("LayoutInflater parameters cannot be null", resDirs, attrInfo, widgetInfo, resFinder); } @Override diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/AttributeResource.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/AttributeResource.java deleted file mode 100644 index 12c1e5536..000000000 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/AttributeResource.java +++ /dev/null @@ -1,122 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * -**************************************************************************************/ -package com.itsaky.androidide.ui.resources; - -import androidx.annotation.NonNull; -import java.util.regex.Pattern; - -public class AttributeResource { - public static final String ANDROID_NS = "http://schemas.android.com/apk/res/android"; - public static final String ANDROID_RES_NS_PREFIX = "http://schemas.android.com/apk/res/"; - public static final String RES_AUTO_NS_URI = "http://schemas.android.com/apk/res-auto"; - - public static final String NULL_VALUE = "@null"; - public static final String EMPTY_VALUE = "@empty"; - public static final Pattern IS_RESOURCE_REFERENCE = Pattern.compile("^\\s*@"); - - public final @NonNull ResName resName; - public final @NonNull String value; - public final @NonNull String trimmedValue; - public final @NonNull String contextPackageName; - private final Integer referenceResId; - - public AttributeResource(@NonNull ResName resName, @NonNull String value, @NonNull String contextPackageName) { - this(resName, value, contextPackageName, null); - } - - public AttributeResource(@NonNull ResName resName, @NonNull String value, @NonNull String contextPackageName, Integer referenceResId) { - this.referenceResId = referenceResId; - if (!resName.type.equals("attr")) throw new IllegalStateException("\"" + resName.getFullyQualifiedName() + "\" unexpected"); - - this.resName = resName; - this.value = value; - this.trimmedValue = value.trim(); - this.contextPackageName = contextPackageName; - } - - public boolean isResourceReference() { - return isResourceReference(trimmedValue); - } - - public @NonNull ResName getResourceReference() { - if (!isResourceReference()) throw new RuntimeException("not a resource reference: " + this); - return ResName.qualifyResName(deref(trimmedValue).replace("+", ""), contextPackageName, "style"); - } - - public boolean isStyleReference() { - return isStyleReference(trimmedValue); - } - - public ResName getStyleReference() { - if (!isStyleReference()) throw new RuntimeException("not a style reference: " + this); - return ResName.qualifyResName(value.substring(1), contextPackageName, "attr"); - } - - public boolean isNull() { - return NULL_VALUE.equals(trimmedValue); - } - - public boolean isEmpty() { - return EMPTY_VALUE.equals(trimmedValue); - } - - @Override - public String toString() { - return "Attribute{" + - "name='" + resName + '\'' + - ", value='" + value + '\'' + - ", contextPackageName='" + contextPackageName + '\'' + - '}'; - } - - public static boolean isResourceReference(String value) { - return IS_RESOURCE_REFERENCE.matcher(value).find() && !isNull(value); - } - - public static @NonNull ResName getResourceReference(String value, String defPackage, String defType) { - if (!isResourceReference(value)) throw new IllegalArgumentException("not a resource reference: " + value); - return ResName.qualifyResName(deref(value).replace("+", ""), defPackage, defType); - } - - private static @NonNull String deref(@NonNull String value) { - return value.substring(value.indexOf('@') + 1); - } - - public static boolean isStyleReference(String value) { - return value.startsWith("?"); - } - - public static ResName getStyleReference(String value, String defPackage, String defType) { - if (!isStyleReference(value)) throw new IllegalArgumentException("not a style reference: " + value); - return ResName.qualifyResName(value.substring(1), defPackage, defType); - } - - public static boolean isNull(String value) { - return NULL_VALUE.equals(value); - } - - public static boolean isEmpty(String value) { - return EMPTY_VALUE.equals(value); - } - - public Integer getReferenceResId() { - return referenceResId; - } -} diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/ResName.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/ResName.java deleted file mode 100644 index d349235ac..000000000 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/ResName.java +++ /dev/null @@ -1,189 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * -**************************************************************************************/ -package com.itsaky.androidide.ui.resources; - -import androidx.annotation.NonNull; -import java.io.File; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class ResName { - public static final String ID_TYPE = "id"; - - private static final Pattern FQN_PATTERN = Pattern.compile("^([^:]*):([^/]+)/(.+)$"); - private static final int NAMESPACE = 1; - private static final int TYPE = 2; - private static final int NAME = 3; - - public final @NonNull String packageName; - public final @NonNull String type; - public final @NonNull String name; - - public final int hashCode; - - public ResName(@NonNull String packageName, @NonNull String type, @NonNull String name) { - this.packageName = packageName; - this.type = type.trim(); - this.name = name.trim(); - - hashCode = computeHashCode(); - } - - public ResName(@NonNull String fullyQualifiedName) { - Matcher matcher = FQN_PATTERN.matcher(fullyQualifiedName.trim()); - if (!matcher.find()) { - throw new IllegalStateException("\"" + fullyQualifiedName + "\" is not fully qualified"); - } - packageName = matcher.group(NAMESPACE); - type = matcher.group(TYPE).trim(); - name = matcher.group(NAME).trim(); - - hashCode = computeHashCode(); - if (packageName.equals("xmlns")) throw new IllegalStateException("\"" + fullyQualifiedName + "\" unexpected"); - } - - /** - * @return null if the resource could not be qualified. - */ - public static String qualifyResourceName(@NonNull String possiblyQualifiedResourceName, String defaultPackageName, String defaultType) { - ResName resName = qualifyResName(possiblyQualifiedResourceName, defaultPackageName, defaultType); - return resName != null ? resName.getFullyQualifiedName() : null; - } - - public static ResName qualifyResName(@NonNull String possiblyQualifiedResourceName, ResName defaults) { - return qualifyResName(possiblyQualifiedResourceName, defaults.packageName, defaults.type); - } - - public static ResName qualifyResName(@NonNull String possiblyQualifiedResourceName, String defaultPackageName, String defaultType) { - int indexOfColon = possiblyQualifiedResourceName.indexOf(':'); - int indexOfSlash = possiblyQualifiedResourceName.indexOf('/'); - String type = null; - String packageName = null; - String name = possiblyQualifiedResourceName; - if (indexOfColon > indexOfSlash) { - if (indexOfSlash > 0) { - type = possiblyQualifiedResourceName.substring(0, indexOfSlash); - } - packageName = possiblyQualifiedResourceName.substring(indexOfSlash + 1, indexOfColon); - name = possiblyQualifiedResourceName.substring(indexOfColon + 1); - } else if (indexOfSlash > indexOfColon) { - if (indexOfColon > 0) { - packageName = possiblyQualifiedResourceName.substring(0, indexOfColon); - } - type = possiblyQualifiedResourceName.substring(indexOfColon + 1, indexOfSlash); - name = possiblyQualifiedResourceName.substring(indexOfSlash + 1); - } - - if ((type == null && defaultType == null) || (packageName == null && defaultPackageName == null)) { - return null; - } - - if (packageName == null) { - packageName = defaultPackageName; - } else if ("*android".equals(packageName)) { - packageName = "android"; - } - - return new ResName(packageName, type == null ? defaultType : type, name); - } - - public static String qualifyResName(String possiblyQualifiedResourceName, String contextPackageName) { - if (possiblyQualifiedResourceName == null) { - return null; - } - - if (AttributeResource.isNull(possiblyQualifiedResourceName)) { - return null; - } - - // Was not able to fully qualify the resource name - String fullyQualifiedResourceName = qualifyResourceName(possiblyQualifiedResourceName, contextPackageName, null); - if (fullyQualifiedResourceName == null) { - return null; - } - - return fullyQualifiedResourceName.replaceAll("[@+]", ""); - } - - public static ResName qualifyFromFilePath(@NonNull final String packageName, @NonNull final String filePath) { - final File file = new File(filePath); - final String type = file.getParentFile().getName().split("-", 0)[0]; - final String name = baseNameFor(file.getName()); - - return new ResName(packageName, type, name); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ResName resName = (ResName) o; - - if (hashCode() != resName.hashCode()) return false; - - if (!packageName.equals(resName.packageName)) return false; - if (!type.equals(resName.type)) return false; - if (!name.equals(resName.name)) return false; - - return true; - } - - @Override - public int hashCode() { - return hashCode; - } - - @Override - public String toString() { - return "ResName{" + getFullyQualifiedName() + "}"; - } - - public String getFullyQualifiedName() { - return packageName + ":" + type + "/" + name; - } - - public String getNamespaceUri() { - return "http://schemas.android.com/apk/res/" + packageName; - } - - public ResName withPackageName(String packageName) { - if (packageName.equals(this.packageName)) return this; - return new ResName(packageName, type, name); - } - - public void mustBe(String expectedType) { - if (!type.equals(expectedType)) { - throw new RuntimeException("expected " + getFullyQualifiedName() + " to be a " + expectedType + ", is a " + type); - } - } - - private int computeHashCode() { - int result = packageName.hashCode(); - result = 31 * result + type.hashCode(); - result = 31 * result + name.hashCode(); - return result; - } - - static String baseNameFor(String name) { - int dotIndex = name.indexOf("."); - return dotIndex >= 0 ? name.substring(0, dotIndex) : name; - } -} diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/ResourceIdGenerator.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/ResourceIdGenerator.java deleted file mode 100644 index 29c4c834f..000000000 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/ResourceIdGenerator.java +++ /dev/null @@ -1,80 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * -**************************************************************************************/ -package com.itsaky.androidide.ui.resources; - -import java.util.HashMap; -import java.util.Map; - -public class ResourceIdGenerator { - - private final Map typeInfo = new HashMap<>(); - private int packageIdentifier; - - private static class TypeTracker { - private int typeIdentifier; - private int currentMaxEntry; - - TypeTracker(int typeIdentifier) { - this.typeIdentifier = typeIdentifier; - } - - void record(int entryIdentifier) { - currentMaxEntry = Math.max(currentMaxEntry, entryIdentifier); - } - - public int getFreeIdentifier() { - return ++currentMaxEntry; - } - - public int getTypeIdentifier() { - return typeIdentifier; - } - } - - ResourceIdGenerator(int packageIdentifier) { - this.packageIdentifier = packageIdentifier; - } - - public void record(int resId, String type, String name) { - TypeTracker typeTracker = typeInfo.get(type); - if (typeTracker == null) { - typeTracker = new TypeTracker(ResourceIds.getTypeIdentifier(resId)); - typeInfo.put(type, typeTracker); - } - typeTracker.record(ResourceIds.getEntryIdentifier(resId)); - } - - public int generate(String type, String name) { - TypeTracker typeTracker = typeInfo.get(type); - if (typeTracker == null) { - typeTracker = new TypeTracker(getNextFreeTypeIdentifier()); - typeInfo.put(type, typeTracker); - } - return ResourceIds.makeIdentifer(packageIdentifier, typeTracker.getTypeIdentifier(), typeTracker.getFreeIdentifier()); - } - - private int getNextFreeTypeIdentifier() { - int result = 0; - for (TypeTracker typeTracker : typeInfo.values()) { - result = Math.max(result, typeTracker.getTypeIdentifier()); - } - return ++result; - } -} diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/ResourceIds.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/ResourceIds.java deleted file mode 100644 index 6d72960a7..000000000 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/ResourceIds.java +++ /dev/null @@ -1,42 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * -**************************************************************************************/ -package com.itsaky.androidide.ui.resources; - -public class ResourceIds { - public static boolean isFrameworkResource(int resId) { - return ((resId >>> 24) == 0x1); - } - - public static int getPackageIdentifier(int resId) { - return (resId >>> 24); - } - - public static int getTypeIdentifier(int resId) { - return (resId & 0x00FF0000) >>> 16; - } - - public static int getEntryIdentifier(int resId) { - return resId & 0x0000FFFF; - } - - public static int makeIdentifer(int packageIdentifier, int typeIdentifier, int entryIdenifier) { - return packageIdentifier << 24 | typeIdentifier << 16 | entryIdenifier; - } -} diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/ResourceTable.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/ResourceTable.java deleted file mode 100644 index eda013f08..000000000 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/ResourceTable.java +++ /dev/null @@ -1,70 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * -**************************************************************************************/ -package com.itsaky.androidide.ui.resources; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; - -public class ResourceTable { - - private int packageIdentifier = 0; - private final String packageName; - private final BiMap resourceTable = HashBiMap.create(); - - private final ResourceIdGenerator androidResourceIdGenerator = new ResourceIdGenerator(0x01); - - public ResourceTable(String packageName) { - this.packageName = packageName; - } - - public Integer getResourceId(ResName resName) { - Integer id = resourceTable.inverse().get(resName); - if (id == null && resName != null && resName.name.contains(".")) { - id = resourceTable.inverse().get(new ResName(resName.packageName, resName.type, underscorize(resName.name))); - } - return id != null ? id : 0; - } - - public int getPackageIdentifier() { - return packageIdentifier; - } - - void addResource(int resId, String type, String name) { - if (ResourceIds.isFrameworkResource(resId)) { - androidResourceIdGenerator.record(resId, type, name); - } - ResName resName = new ResName(packageName, type, name); - int resIdPackageIdentifier = ResourceIds.getPackageIdentifier(resId); - if (getPackageIdentifier() == 0) { - this.packageIdentifier = resIdPackageIdentifier; - } else if (getPackageIdentifier() != resIdPackageIdentifier) { - throw new IllegalArgumentException("Incompatible package for " + packageName + ":" + type + "/" + name + " with resId " + resIdPackageIdentifier + " to ResourceIndex with packageIdentifier " + getPackageIdentifier()); - } - - ResName existingEntry = resourceTable.put(resId, resName); - if (existingEntry != null && !existingEntry.equals(resName)) { - throw new IllegalArgumentException("ResId " + Integer.toHexString(resId) + " mapped to both " + resName + " and " + existingEntry); - } - } - - private static String underscorize(String s) { - return s == null ? null : s.replace('.', '_'); - } -} diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/ResourceTableFactory.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/ResourceTableFactory.java deleted file mode 100644 index 6a58413c1..000000000 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/resources/ResourceTableFactory.java +++ /dev/null @@ -1,123 +0,0 @@ -/************************************************************************************ - * This file is part of AndroidIDE. - * - * - * - * AndroidIDE is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * AndroidIDE is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with AndroidIDE. If not, see . - * -**************************************************************************************/ -package com.itsaky.androidide.ui.resources; - -import androidx.annotation.Nullable; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ResourceTableFactory { - - @Nullable - public static ResourceTable newFrameworkResourceTable () { - final ResourceTable table = new ResourceTable ("android"); - final Class androidR = android.R.class; - try { - processResources(table, androidR); - } catch (IllegalArgumentException|IllegalAccessException e) { - return null; - } - return table; - } - - private static void processResources(ResourceTable table, Class rClass) throws IllegalArgumentException, IllegalAccessException { - final Map> styleableMap = new HashMap<>(); - for (Class innerClass : rClass.getClasses()) { - if ("styleable".equals(innerClass.getSimpleName())) { - for (final Field attr : innerClass.getDeclaredFields()) { - final Class attrClassType = attr.getType(); - if (attrClassType == int[].class) { // declaration - addStyleableGroup (styleableMap, attr); - } else if (attrClassType == int.class) { // Member of - addStyleableMember (table, styleableMap, attr); - } - } - } else { - for (Field field : innerClass.getDeclaredFields()) { - if (field.getType().equals(Integer.TYPE) && Modifier.isStatic(field.getModifiers())) { - int id = field.getInt(null); - String resourceName = field.getName(); - if (id != 0) { - table.addResource(id, innerClass.getSimpleName(), resourceName); - } - } - } - } - } - } - - private static void addStyleableGroup(final Map> styleableMap, final Field attr) throws IllegalArgumentException, IllegalAccessException { - final String name = attr.getName(); - List members = styleableMap.get(name); - if (members == null) { - members = new ArrayList<>(); - } - final int[] mm = (int[]) attr.get(null); - if (mm == null || mm.length <= 0) { - return; - } - - for (int i=0;i> styleableMap, final Field attr) throws IllegalArgumentException, IllegalAccessException { - final String name = attr.getName(); - final int separator = findGroupAndAttrNameSeparator (styleableMap, name); // If this is a member, then the name will definitely contain am underscore - final String groupName = name.substring(0, separator); - final String attrName = name.substring(separator + 1); - - final List members = styleableMap.get(groupName); - if (members == null) { - throw new IllegalStateException ("No styleable declared for " + groupName + "\nstyleableMap = " + styleableMap); // No entry for this name - } - - final int index = (int) attr.get(null); - if (index < 0 || index >= members.size()) { - throw new IndexOutOfBoundsException ("Index " + index + " is out of bounds (size=" + members.size() + "). name=" + name + ", grpName=" + groupName + ", attrName=" + attrName); - } - - table.addResource(members.get(index), "attr", attrName); - } - - private static int findGroupAndAttrNameSeparator(Map> styleableMap, String name) { - int index = name.length() - 1; - - while (index > 0) { - int i = name.lastIndexOf("_", index); - String group = name.substring(0, i); - List mm = styleableMap.get(group); - if (mm != null) { - return i; - } else { - index = i - 1; - } - } - - return -1; - } -} diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/IView.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/IView.java index cc8c61f59..694b5f577 100644 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/IView.java +++ b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/IView.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. * - * - * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/IViewGroup.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/IViewGroup.java index 50164ece4..3eec14c28 100644 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/IViewGroup.java +++ b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/IViewGroup.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. - * - * - * + * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/BaseViewAttrAdapter.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/BaseViewAttrAdapter.java index dfd5131be..50554721d 100644 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/BaseViewAttrAdapter.java +++ b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/BaseViewAttrAdapter.java @@ -1,7 +1,5 @@ /************************************************************************************ - * This file is part of AndroidIDE. - * - * + * This file is part of AndroidIDE * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,6 +34,7 @@ import androidx.core.view.GravityCompat; import com.itsaky.androidide.ui.inflater.IResourceFinder; import com.itsaky.androidide.ui.view.IAttribute; import com.itsaky.androidide.ui.view.IAttributeAdapter; +import com.itsaky.androidide.utils.Logger; import java.io.File; import java.lang.reflect.Field; import java.util.regex.Pattern; @@ -47,34 +46,40 @@ public class BaseViewAttrAdapter implements IAttributeAdapter { private final Pattern HEX_COLOR = Pattern.compile("#[a-fA-F0-9]{6,8}"); + protected static final Logger LOG = Logger.instance ("BaseViewAttrAdapter"); public static final int ENUM_NOT_FOUND = -4116; @Override public boolean isApplicableTo(View view) { - return true; + return true; // Can be applied to any view } @Override public boolean apply(IAttribute attribute, View view, IResourceFinder resFinder) { final String namespace = attribute.getNamespace(); - final String name = attribute.getNamespace(); + final String name = attribute.getAttributeName(); final String value = attribute.getValue(); final ViewGroup.LayoutParams params = view.getLayoutParams(); final Resources res = view.getResources(); final DisplayMetrics dm = res.getDisplayMetrics(); final Context ctx = view.getContext(); - if (canHandleNamespace(namespace)) { + if (!canHandleNamespace(namespace)) { + LOG.error("Cannot handle namespace: " + namespace); return false; } + LOG.debug ("Adding attribute", attribute); + boolean handled = true; switch (name) { case "layout_height" : params.height = parseDimension (value, -2, dm, resFinder); + LOG.error("Added layout_height", params.height); break; case "layout_width" : params.width = parseDimension (value, -2, dm, resFinder); + LOG.error("Added layout_width", params.width); break; case "alpha" : view.setAlpha(parseFloat(value)); @@ -221,33 +226,12 @@ public class BaseViewAttrAdapter implements IAttributeAdapter { break; } - // In case these attributes are related to margins - // We need to apply them by casting the params to ViewGroup.MarginLayoutParams - if (!handled && params instanceof ViewGroup.MarginLayoutParams) { - ViewGroup.MarginLayoutParams marginParams = (ViewGroup.MarginLayoutParams) params; - switch (name) { - case "layout_margin" : - final int margin = parseDimension(value, 0, dm, resFinder); - marginParams.setMargins(margin, margin, margin, margin); - break; - case "layout_marginLeft" : - marginParams.leftMargin = parseDimension(value, 0, dm, resFinder); - break; - case "layout_marginTop" : - marginParams.topMargin = parseDimension(value, 0, dm, resFinder); - break; - case "layout_marginRight" : - marginParams.rightMargin = parseDimension(value, 0, dm, resFinder); - break; - case "layout_marginBottom" : - marginParams.bottomMargin = parseDimension(value, 0, dm, resFinder); - break; - case "layout_marginStart" : - marginParams.setMarginStart(parseDimension(value, 0, dm, resFinder)); - break; - case "layout_marginEnd" : - marginParams.setMarginEnd(parseDimension(value, 0, dm, resFinder)); - break; + // ----- Handle attributes related to parent ------ + if (!handled) { + + // Layout Margins + if (params instanceof ViewGroup.MarginLayoutParams) { + handleMarginParams((ViewGroup.MarginLayoutParams) params, name, value, dm, resFinder); } } @@ -255,6 +239,33 @@ public class BaseViewAttrAdapter implements IAttributeAdapter { return handled; } + + private void handleMarginParams(ViewGroup.MarginLayoutParams params, String name, String value, DisplayMetrics dm, IResourceFinder resFinder) { + switch (name) { + case "layout_margin" : + final int margin = parseDimension(value, 0, dm, resFinder); + params.setMargins(margin, margin, margin, margin); + break; + case "layout_marginLeft" : + params.leftMargin = parseDimension(value, 0, dm, resFinder); + break; + case "layout_marginTop" : + params.topMargin = parseDimension(value, 0, dm, resFinder); + break; + case "layout_marginRight" : + params.rightMargin = parseDimension(value, 0, dm, resFinder); + break; + case "layout_marginBottom" : + params.bottomMargin = parseDimension(value, 0, dm, resFinder); + break; + case "layout_marginStart" : + params.setMarginStart(parseDimension(value, 0, dm, resFinder)); + break; + case "layout_marginEnd" : + params.setMarginEnd(parseDimension(value, 0, dm, resFinder)); + break; + } + } protected boolean canHandleNamespace(String namespace) { // TODO Compare namespace URI instead of name @@ -428,7 +439,7 @@ public class BaseViewAttrAdapter implements IAttributeAdapter { case "drawable" : return ContextCompat.getDrawable(ctx, id); default : - return newTransparentDrawable(); + return newTransparentDrawable(); } } @@ -462,7 +473,9 @@ public class BaseViewAttrAdapter implements IAttributeAdapter { if (HEX_COLOR.matcher(color).matches()) { try { return Color.parseColor(color); - } catch (Throwable th) {} + } catch (Throwable th) { + // Ignored + } } else if (color.startsWith("@color/")) { return parseColor(resFinder.findColor(color.substring("@color/".length())), resFinder, ctx); } else if (color.startsWith("@android:color/")) { diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/BaseViewGroupAttrAdapter.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/BaseViewGroupAttrAdapter.java index 67c305069..8b8b9acbd 100644 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/BaseViewGroupAttrAdapter.java +++ b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/BaseViewGroupAttrAdapter.java @@ -43,7 +43,7 @@ public class BaseViewGroupAttrAdapter extends BaseViewAttrAdapter { } final ViewGroup group = (ViewGroup) view; final String namespace = attribute.getNamespace(); - final String name = attribute.getNamespace(); + final String name = attribute.getAttributeName(); final String value = attribute.getValue(); if (!canHandleNamespace(namespace)) { diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/ButtonAttrAdapter.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/ButtonAttrAdapter.java index ec02311fe..987cf4966 100644 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/ButtonAttrAdapter.java +++ b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/ButtonAttrAdapter.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. - * - * - * + * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/LinearLayoutAttrAdapter.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/LinearLayoutAttrAdapter.java index 17f709291..8f9e43777 100644 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/LinearLayoutAttrAdapter.java +++ b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/LinearLayoutAttrAdapter.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. * - * - * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -43,7 +41,7 @@ public class LinearLayoutAttrAdapter extends BaseViewGroupAttrAdapter { final LinearLayout linear = (LinearLayout) view; final String namespace = attribute.getNamespace(); - final String name = attribute.getNamespace(); + final String name = attribute.getAttributeName(); final String value = attribute.getValue(); if (!canHandleNamespace(namespace)) { diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/TextViewAttrAdapter.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/TextViewAttrAdapter.java index 7b582e5a2..8bbceebd7 100644 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/TextViewAttrAdapter.java +++ b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/adapters/TextViewAttrAdapter.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. - * - * - * + * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -50,7 +48,7 @@ public class TextViewAttrAdapter extends BaseViewAttrAdapter { final TextView text = (TextView) view; final String namespace = attribute.getNamespace(); - final String name = attribute.getNamespace(); + final String name = attribute.getAttributeName(); final String value = attribute.getValue(); final ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams(); final Resources res = view.getResources(); @@ -59,7 +57,7 @@ public class TextViewAttrAdapter extends BaseViewAttrAdapter { final Drawable[] drawables = text.getCompoundDrawables(); final Drawable[] drawablesRelative = text.getCompoundDrawablesRelative(); - if (canHandleNamespace(namespace)) { + if (!canHandleNamespace(namespace)) { return false; } diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/BaseView.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/BaseView.java index 17fd1aae2..3ad52e1a8 100644 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/BaseView.java +++ b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/BaseView.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. * - * - * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -29,10 +27,11 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.Objects; public abstract class BaseView implements IView { - protected final List attributes = new ArrayList<>(); + protected final Set attributes = new HashSet<>(); protected final Set attrAdapters = new HashSet<>(); protected final String qualifiedName; @@ -83,14 +82,13 @@ public abstract class BaseView implements IView { this.attributes.add(attr); for (IAttributeAdapter adapter : attrAdapters) { - if (adapter.isApplicableTo(asView())) { - if (adapter.apply(attr, asView(), resFinder)) { + if (adapter.isApplicableTo(asView()) + && adapter.apply(attr, asView(), resFinder)) { break; - } } } } - + @Override public void removeAttribute(IAttribute attr) { this.attributes.remove(attr); @@ -121,16 +119,18 @@ public abstract class BaseView implements IView { return false; } - if (obj instanceof IView) { - IView that = (IView) obj; - return this.asView().equals(that.asView()); - } - - return false; + return this.hashCode() == obj.hashCode(); } @Override public int hashCode() { - return asView().hashCode(); + return Objects.hash( + attributes, + attrAdapters, + qualifiedName, + view, + parent, + isPlaceholder + ); } } diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/BaseViewGroup.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/BaseViewGroup.java index 2c4e056d8..239cf839e 100644 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/BaseViewGroup.java +++ b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/BaseViewGroup.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. - * - * - * + * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/UiAttribute.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/UiAttribute.java index 3b9c8c9fd..e47321003 100644 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/UiAttribute.java +++ b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/UiAttribute.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. - * - * - * + * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -24,6 +22,7 @@ import com.itsaky.androidide.ui.view.IAttribute; import com.itsaky.androidide.ui.view.IFixedValue; import java.util.HashSet; import java.util.Set; +import java.util.Objects; public class UiAttribute implements IAttribute { @@ -76,18 +75,14 @@ public class UiAttribute implements IAttribute { @Override public boolean equals(Object obj) { - if (obj instanceof UiAttribute) { - UiAttribute that = (UiAttribute) obj; - return this.getNamespace().equals(that.getNamespace()) - && this.getAttributeName().equals(that.getAttributeName()) - && this.getValue().equals(that.getValue()) - && this.getFixedValues().equals(that.getFixedValues()); + if (obj == null) { + return false; } - return false; + return this.hashCode() == obj.hashCode(); } @Override public int hashCode() { - return toString().hashCode(); + return Objects.hash(namespace, name, value, fixedValues); } } diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/UiView.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/UiView.java index d7d7bc560..e004afbc8 100644 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/UiView.java +++ b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/UiView.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. - * - * - * + * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or diff --git a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/UiViewGroup.java b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/UiViewGroup.java index 86b6b2fb7..61c436a38 100644 --- a/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/UiViewGroup.java +++ b/layout-inflater/src/main/java/com/itsaky/androidide/ui/view/impl/UiViewGroup.java @@ -1,8 +1,6 @@ /************************************************************************************ * This file is part of AndroidIDE. * - * - * * AndroidIDE is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or